你可以将lambda表达式作为参数传递,但是你需要使用一些委托类型进行限定(例如System.Action
、System.Func
等)
以下代码对我有效:
var typeParamOne = typeof(string);
var typeParamTwo = typeof(string);
// we could do new Action<string>(s => MyClass.MyMethod(s));
// but why bother when the method signature matches already
var callbackMethod = new Action<string>(MyClass.MyMethod);
var type = typeof(SomeFrameworkType<,>);
var constructed = type.MakeGenericType(typeParamOne, typeParamTwo);
var instance = Activator.CreateInstance(constructed, callbackMethod);
var castedInstance = (SomeFrameworkType<string, string>)instance;
castedInstance.CallTheCallback();
实际上,我们根本不需要使用
Activator.CreateInstance
- 我们只需要获取我们想要的特定构造函数,然后调用它即可。如果我们正在创建许多相同类型的对象实例,这将更快。例如:
var type = typeof(SomeFrameworkType<,>);
var constructed = type.MakeGenericType(typeParamOne, typeParamTwo);
var constructor = constructed.GetConstructor(new[]{ typeof(Action<string>) });
var instance = constructor.Invoke(new object[] { callbackMethod });
如果您想在不进行强制转换的情况下调用instance
上的方法,该怎么办?只需使用InvokeMember
即可,如下所示
constructed.InvokeMember(
"CallTheCallback",
BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public,
null,
instance,
null);
如果你不知道需要哪种回调方法,那么似乎会有问题,因为你总是想调用已知类型的MyClass.MyMethod
。例如:如果SomeFrameworkType<int, int>
的构造函数要求你还传递一个Action<int>
类型的委托,则这与可能需要一个字符串参数的MyClass.MyMethod
不匹配。
你需要执行以下操作之一:
- 创建一些额外的包装器方法,将int转换为字符串(或类似内容),然后在创建instance
时传递这些包装器方法
- 创建许多重载的MyClass.MyMethod
,具有不同的参数类型,并具有选择正确方法的某些逻辑
- 使MyClass.MyMethod
成为泛型,并执行以下操作:
// create the delegate type so we can find the appropriate constructor
var delegateType = typeof(Action<>).MakeGenericType(typeParamOne);
// work out concrete type for calling the generic MyMethod
var myMethodType = typeof(MyClass)
.GetMethod("MyMethod")
.MakeGenericMethod(typeParamOne);
// create an instance of the delegate type wrapping MyMethod so we can pass it to the constructor
var delegateInstance = Delegate.CreateDelegate(delegateType, myMethodType);
var type = typeof(SomeFrameworkType<,>);
var constructed = type.MakeGenericType(typeParamOne, typeParamTwo);
var instance = Activator.CreateInstance(constructed, delegateInstance);