C# 将具有泛型方法的接口实例转换为操作

C# 将具有泛型方法的接口实例转换为操作,c#,generics,reflection,delegates,action,C#,Generics,Reflection,Delegates,Action,我正在努力使用我可以使用反射检索的MethodInfo创建Action的实例 使用下面的示例,我可以轻松地对对象调用自定义方法,但我确实希望将它们转换为操作 我尝试过使用Delegate.CreateDelegate来执行此操作,但我似乎无法让它返回具有泛型类型的操作 示例 我创建了以下界面: interface IMyTest { } // Marker interface interface<TInput> IMyTest : IMyTest { void MyMetho

我正在努力使用我可以使用反射检索的
MethodInfo
创建
Action
的实例

使用下面的示例,我可以轻松地对对象调用自定义方法,但我确实希望将它们转换为操作

我尝试过使用
Delegate.CreateDelegate
来执行此操作,但我似乎无法让它返回具有泛型类型的操作

示例

我创建了以下界面:

interface IMyTest { } // Marker interface
interface<TInput> IMyTest : IMyTest {
    void MyMethod(TInput input);
}
我想要的

DoCallMyMethod
内部,我希望将
MethodInfo方法
转换为通用的
操作
,结果如下:

Action<type> myAction = method;
MyClass foo = new MyClass();
var action1 = DoCallMyMethod<DateTime>(foo);
var action2 = DoCallMyMethod<int>(foo);

action1(DateTime.Now);
action2(47);
Action myAction=method;
但这显然不起作用

我发现了一些类似的SO帖子(但没有一篇完全涵盖我的情况),最终得到了类似的答案:

Action<object> action = 
    (Action<object>)Delegate.CreateDelegate(typeof(Action<object>), target, method);
动作动作=
(Action)Delegate.CreateDelegate(类型(Action)、目标、方法);
但这不起作用,因为“无法绑定到目标方法,因为其签名或安全透明性与委托类型的签名或安全透明性不兼容。”


如何获取指定的
类型为其输入类型的操作,同时仍保留对象引用(没有出现新实例)?

您无法从
MyMethod
中的一个创建
操作,因为该方法需要特定对象的类型(
int
DateTime
)如果将其视为
操作
,则可以使用任何类型的对象调用它

由于您需要的是返回一个
操作
,因此不需要将输入值传递给
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;
}
public Action DoCallMyMethod(对象目标)
{
var@interface=typeof(IMyTest);
if(@interface.IsAssignableFrom(target.GetType()))
{
var method=@interface.GetMethod(“MyMethod”);
if(方法!=null)
{
var action=Delegate.CreateDelegate(typeof(action)、target、method)作为action;
返回动作;
}
}
返回null;
}
然后,像这样使用它:

Action<type> myAction = method;
MyClass foo = new MyClass();
var action1 = DoCallMyMethod<DateTime>(foo);
var action2 = DoCallMyMethod<int>(foo);

action1(DateTime.Now);
action2(47);
MyClass foo=newmyclass();
var action1=DoCallMyMethod(foo);
var action2=DoCallMyMethod(foo);
动作1(DateTime.Now);
行动2(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;
}
public委托DoCallMyMethod(对象目标,输入类型)
{
var@interface=typeof(IMyTest)。MakeGenericType(inputType);
if(@interface.IsAssignableFrom(target.GetType()))
{
var method=@interface.GetMethod(“MyMethod”);
if(方法!=null)
{
var@delegate=delegate.CreateDelegate(typeof(Action).MakeGenericType(inputType),目标,方法);
return@delegate;
}
}
返回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);
MyClass foo=newmyclass();
var action1=DoCallMyMethod(foo,typeof(DateTime))作为操作;
var action2=DoCallMyMethod(foo,typeof(int))作为Action;
动作1(DateTime.Now);
行动2(47);
//或
int输入=47;
var@delegate=DoCallMyMethod(foo,input.GetType());
@delegate.DynamicInvoke(输入);
但是,如果需要返回一个
操作
,则可以执行一个操作,接收一个对象并在该对象的类型有效时调用该方法:

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;
}
public Action DoCallMyMethod(对象目标,输入类型)
{
var@interface=typeof(IMyTest)。MakeGenericType(inputType);
if(@interface.IsAssignableFrom(target.GetType()))
{
var method=@interface.GetMethod(“MyMethod”);
if(方法!=null)
{
Action=obj=>
{
if(obj.GetType().IsAssignableFrom(inputType))
调用(目标,新对象[]{obj});
};
返回动作;
}
}
返回null;
}
而且

MyClass foo = new MyClass();
Action<object> action = DoCallMyMethod(foo, typeof(int));
action(47);         // MyMethod(int) is called.
action("...");      // Nothing happens.
MyClass foo=newmyclass();
Action-Action=DoCallMyMethod(foo,typeof(int));
行动(47);//调用MyMethod(int)。
行动(“…”);//什么也没发生。

现在,您有了一个
操作
,它只在传递整数时调用
MyMethod(int)

它以某种方式工作,但我还需要一个步骤,我无法从您的答案中推断出来(从问题中可能还不清楚)。一旦我拥有了
委托
,而不知道输入的类型,我如何从中获得通用操作?例如,如果我还有一个方法
AddExternalCaller(Action callback)
,那么
回调可以是
MyMethod
的变体之一。然后,我如何让
addernalcaller()
DoCallMyMethod()
列表的全局集合添加操作?@GTHvidsten:但是您不能将
操作
之类的
操作
操作
添加到
列表
,因为
操作
不是
操作
。当传递对象的方法需要
int
时,不能调用该方法。事实上,这在另一个方向上是有效的,因为
Action
是逆变的,您可以将
Action
分配给
Action
变量,您可以调用一个方法,该方法期望对象具有整数。我认为您需要更改保存回调的设计方式。以前我将
Action
转换为
Action
的一种方法是使用以下语法进行转换:
void convert(Action callback){Action foo=input=>callback((T)input);}
。我能够将动态委托转换为如下操作:
Action handler=request=>@delegate.DynamicInvoke(request)。到目前为止,它在我的场景中也起作用。你觉得这有什么特别的缺点吗?@GTHvidsten如果
MyClass foo = new MyClass();
Action<object> action = DoCallMyMethod(foo, typeof(int));
action(47);         // MyMethod(int) is called.
action("...");      // Nothing happens.