Delegate.CreateDelegate() and generics: Error bind

2019-01-19 00:06发布

问题:

I'm having problems creating a collection of delegate using reflection and generics.

I'm trying to create a delegate collection from Ally methods, whose share a common method signature.

public class Classy
{
  public string FirstMethod<T1, T2>( string id, Func<T1, int, IEnumerable<T2>> del );
  public string SecondMethod<T1, T2>( string id, Func<T1, int, IEnumerable<T2>> del );    
  public string ThirdMethod<T1, T2>( string id, Func<T1, int, IEnumerable<T2>> del );

  // And so on...
}

And the generics cooking:

// This is the Classy's shared method signature    
public delegate string classyDelegate<out T1, in T2>( string id, Func<T1, int, IEnumerable<T2>> filter );


// And the linq-way to get the collection of delegates from Classy
( 
   from method in typeof( Classy ).GetMethods( BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic )
   let delegateType = typeof( classyDelegate<,> )
   select Delegate.CreateDelegate( delegateType, method )
).ToList( );

But the Delegate.CreateDelegate( delegateType, method ) throws an ArgumentException saying Error binding to target method. : /

What am I doing wrong?

回答1:

That is because the overload of Delegate.CreateDelegate only supports creating delegates pointing to static methods. If you want to bind to instance methods, you also need to pass in the instance on which your created delegate is supposed to call the method.

You probably want:

from method in typeof( Classy ).GetMethods( BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic )
let delegateType = typeof( classyDelegate<,> )
select Delegate.CreateDelegate( delegateType, yourInstance, method )

Also, your code example won't compile. You can't declare variance on method signatures; and you can't omit the implementation in a non-abstract class.

Finally, Delegate.CreateDelegate creates a Delegate instance, which cannot exist without knowing it's type parameters. Therefore, you cannot bind to classyDelegate<,>, you need to know the actual types involved.