我正在努力使用我可以使用反射检索的Action<>
来创建MethodInfo
的实例。
使用下面的示例,我可以轻松地在我的对象上调用自定义方法,但我真的想将它们转换为Actions。
我尝试过使用Delegate.CreateDelegate
,但我似乎无法通过泛型返回Action。
示例
我创建了以下界面:
interface IMyTest { } // Marker interface
interface<TInput> IMyTest : IMyTest {
void MyMethod(TInput input);
}
然后我继承了类中的接口:
class MyClass : IMyTest<DateTime>, IMyTest<int> {
void MyMethod(DateTime input) {
// Do something
}
void MyMethod(int input) {
// Do something else
}
}
然后我创建了一个方法,使用反射从界面实例中查找并调用“MyMethod”:
void DoCallMyMethod(object target, object input) {
IEnumerable<Type> interfaces = target.GetType().GetInterfaces()
.Where(x => typeof(IMyTest).IsAssignableFrom(x) && x.IsGenericType);
foreach (Type @interface in interfaces) {
Type type = @interface.GetGenericArguments()[0];
MethodInfo method = @interface.GetMethod("MyMethod", new Type[] { type });
if (method != null) {
method.Invoke(target, new[] { input });
}
}
}
最后我把它们放在一起:
MyClass foo = new MyClass();
DoCallMyMethod(foo, DateTime.Now);
DoCallMyMethod(foo, 47);
我想要什么
在DoCallMyMethod
内,我希望将MethodInfo method
转换为通用Action
,以便结果如下:
Action<type> myAction = method;
但这显然不起作用。
我发现了一些类似的SO帖子(但没有一个完全涵盖我的案例),最终得到了类似的答案:
Action<object> action =
(Action<object>)Delegate.CreateDelegate(typeof(Action<object>), target, method);
但是这不起作用,因为“无法绑定到目标方法,因为它的签名或安全透明度与委托类型的不兼容。”
如何使用指定的type
作为输入类型获取Action,同时仍保留对象引用(不显示新实例)?
答案 0 :(得分:1)
您无法从Action<object>
之一创建MyMethod
,因为该方法需要特定对象的类型(int
,DateTime
如果你将它视为Action<object>
,你可以用任何类型的对象调用它。
由于您需要的是返回Action<T>
,因此无需将输入值传递给DoCallMyMethod
方法。您可以将输入类型作为通用参数传递:
public Action<T> DoCallMyMethod<T>(object target)
{
var @interface = typeof(IMyTest<T>);
if (@interface.IsAssignableFrom(target.GetType()))
{
var method = @interface.GetMethod("MyMethod");
if (method != null)
{
var action = Delegate.CreateDelegate(typeof(Action<T>), target, method) as Action<T>;
return action;
}
}
return null;
}
然后,像这样使用它:
MyClass foo = new MyClass();
var action1 = DoCallMyMethod<DateTime>(foo);
var action2 = DoCallMyMethod<int>(foo);
action1(DateTime.Now);
action2(47);
如果您在编译时不知道输入的类型,可以尝试:
public Delegate DoCallMyMethod(object target, Type inputType)
{
var @interface = typeof(IMyTest<>).MakeGenericType(inputType);
if (@interface.IsAssignableFrom(target.GetType()))
{
var method = @interface.GetMethod("MyMethod");
if (method != null)
{
var @delegate = Delegate.CreateDelegate(typeof(Action<>).MakeGenericType(inputType), target, method);
return @delegate;
}
}
return null;
}
并像这样使用它:
MyClass foo = new MyClass();
var action1 = DoCallMyMethod(foo, typeof(DateTime)) as Action<DateTime>;
var action2 = DoCallMyMethod(foo, typeof(int)) as Action<int>;
action1(DateTime.Now);
action2(47);
//or
int input = 47;
var @delegate = DoCallMyMethod(foo, input.GetType());
@delegate.DynamicInvoke(input);
但是如果你需要返回Action<object>
,你可以做一个接收对象的动作,如果对象的类型有效,则调用该方法:
public Action<object> DoCallMyMethod(object target, Type inputType)
{
var @interface = typeof(IMyTest<>).MakeGenericType(inputType);
if (@interface.IsAssignableFrom(target.GetType()))
{
var method = @interface.GetMethod("MyMethod");
if (method != null)
{
Action<object> action = obj =>
{
if (obj.GetType().IsAssignableFrom(inputType))
method.Invoke(target, new object[] { obj });
};
return action;
}
}
return null;
}
和...
MyClass foo = new MyClass();
Action<object> action = DoCallMyMethod(foo, typeof(int));
action(47); // MyMethod(int) is called.
action("..."); // Nothing happens.
现在你有Action<object>
仅在传递整数时调用MyMethod(int)
。