0

I have a type variable

using System;
using System.Linq;
using System.Reflection;

...

var validateFuncType = typeof(Func<,>).MakeGenericType(someVariableType, typeof(bool));

Now I check if someVariableType follows a convention,

var validateOfType = someVariableType
    .GetMethods(BindingFlags.Instance | BindingFlags.Public)
    .SingleOrDefault(mi =>
        {
            if (mi.Name != "Validate" || mi.ReturnType != typeof(bool))
            {
                return false;
            }

            var parameters = mi.GetParameters();
            return parameters.Length == 0;
        });

then depending on the check

object validateFunc;
if (validateOfType == null)
{
    validateFunc = // some noop func that returns true.
    // e.g.  _ => true;
}
else
{
    validateFunc = // a delegate that calls the conventional validate
    // e.g.  someVariable => someVariable.Validate();
}

instantiate an instance of the delegate type.

Can you help me do that, how can I instantiate validateFuncType, that calls the conventional implementation, if it exists?

Jodrell
  • 34,946
  • 5
  • 87
  • 124
  • BTW: I find it a good practice to prevent using var / always use explicit types. For readability purposes. – Youp Bernoulli Jul 15 '19 at 10:36
  • for a protracted debate on `var` you could start here https://stackoverflow.com/questions/41479/use-of-var-keyword-in-c-sharp – Jodrell Jul 15 '19 at 10:46
  • This is never going to work until the delegate type matches the rest of the code. Which goes hunting for a method with no arguments, so it needs to be `Func<>` instead of `Func<,>`. Or easier yet, just `typeof(Func)`. – Hans Passant Jul 15 '19 at 11:03
  • Think about accepting one of the answers and if these did not satisfy you please stay in the loop and indicate what you are still missing. – Youp Bernoulli Aug 16 '19 at 08:18

3 Answers3

1

If I understand correctly, you are looking for Delegate.CreateDelegate:

var alwaysReturnTrueMethodInfo = typeof(YourClass).GetMethod("AlwaysReturnTrue").MakeGenericMethod(someVariableType);
Delegate validateFunc;
if (validateOfType == null)
{
    validateFunc = Delegate.CreateDelegate(validateFuncType, alwaysReturnTrueMethodInfo);
}
else
{
    validateFunc = Delegate.CreateDelegate(validateFuncType, validateOfType);
}

where AlwaysReturnTrue is a helper static method declared like this:

public static bool AlwaysReturnTrue<T>(T t) { return true }
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • You understand correctly, I made a `bool CallByConventionValidate(dynamic target) { return target.Validate(); }` which seems nasty but also works. – Jodrell Jul 15 '19 at 11:43
  • It was useful, and I learned some good stuff from it but, after noticing the input parameters to `Func<>` are contravariant, I did [something that required less code](https://stackoverflow.com/a/57054000/659190). I'm still not sure what the best answer is. – Jodrell Jul 16 '19 at 09:23
0

You can do it either by:

// create an object of the type
var obj = Activator.CreateInstance(validateFuncType);

And you'll get an instance of validateFuncType in obj.

Another way is to use reflection:

// get public constructors
var ctors = validateFuncType.GetConstructors(BindingFlags.Public);

// invoke the first public constructor with no parameters.
var obj = ctors[0].Invoke(new object[] { });

This was taken from this SO answer. And because of that this question (and answer) might be marked as duplicate.

Youp Bernoulli
  • 5,303
  • 5
  • 39
  • 59
  • but how do I make one that does `_ => true;` and another that does `t => t.Validate();` ? – Jodrell Jul 15 '19 at 10:34
  • Your question is: "how can I instantiate validateFuncType"? That's what I answered. If you want specific (Interface) methods of the type instantiated you need to cast it to a more specific type then "just" Object.Is there a common INterface or base class perhaps for types with the Validate method and return types != bool? The cast the created object to the interface or base class. – Youp Bernoulli Jul 15 '19 at 10:40
  • I clarified the question. – Jodrell Jul 15 '19 at 10:43
0

What I did, after noticing that input parameters for Func<> are contravariant.

object validateFunc = validateOfType != null
                ? config => (bool)validateOfType.Invoke(config, new object[0])
                : new Func<object, bool>(_ => true);

I'm not sure if this is better than @Sweeper's answer

Jodrell
  • 34,946
  • 5
  • 87
  • 124