如何通过反射创建以下内容?
var t = new SomeFrameworkType<string, string>(s => MyClass.MyMethod(s));
这是我到目前为止所拥有的:
var typeParamOne = Type.GetType("System.String");
var typeParamTwo = Type.GetType("System.String");
var myClass= Type.GetType("ConsoleApplication.MyClass");
var myMethod = myClass.GetMethod("MyMethod");
var type = typeof(SomeFrameworkType<,>);
var typeArgs = new[] {typeParamOne, typeParamTwo };
var constructed= type.MakeGenericType(typeArgs);
var instance = Activator.CreateInstance(constructed, myMethod);
样本就是它的样子,因为大多数所需信息都是未知的,并且将作为参数提供。
现在,“实例”分配将抛出异常。我怎样才能适当地传递给构造函数?
另外,我如何将结果转换为SomeFramework,以便在我不知道类型参数时可以使用它?
谢谢!
答案 0 :(得分:3)
假设SomeFrameworkType<,>
定义类似于以下内容:
class SomeFrameworkType<T1, T2> {
public SomeFrameworkType(Func<T1, T2> func) {}
}
且T1
和T2
的泛型类型参数为System.String
(类似于OP的示例),然后可以使用以下方法通过反射实例化代码:
var typeParamOne = typeof (string);
var typeParamTwo = typeof(string);
var myClass = typeof(ConsoleApplication.MyClass);
var myMethod = myClass.GetMethod("MyMethod");
var type = typeof(SomeFrameworkType<,>);
var typeArgs = new[] { typeParamOne, typeParamTwo };
var constructed = type.MakeGenericType(typeArgs);
// construct the delegate
var ctrArgs = typeof(Func<,>).MakeGenericType(typeArgs);
var dlgate = Delegate.CreateDelegate(ctrArgs, myMethod);
var instance = Activator.CreateInstance(constructed, dlgate);
AFAIK ,我们需要至少知道用于将结果object
转换为SomeFrameworkType<,>
的通用类型参数或(如Jon G所指)使用非泛型基本类型SomeFrameworkType<,>
(如果有)。
var casted = instance as SomeFrameworkType<string, string>;
答案 1 :(得分:0)
当构造函数需要一个可能是Action或Func或类似的委托时,您将传递一个MethodInfo作为构造函数参数。
您可以更改SomeFrameworkType以在其构造函数中使用MethodInfo吗?
否则你可以在最后一行中使用类似s =&gt;的myMethod。 myMethod.Invoke(S)
var instance = Activator.CreateInstance(constructed, s => myMethod.Invoke(s));
假设构造函数的委托签名需要返回类型的对象,这应该可行。
Re:转换结果,如果要以强类型方式使用对象,则需要将其转换为编译时知道的类型。如果SomeFrameworkType&lt;,&gt;有一个非泛型的基类型,然后你可以as或括号转换为该类型并使用结果对象。
答案 2 :(得分:0)
您可以将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);