通过反射调用泛型方法。 System.ArgumentException发生

时间:2019-05-18 17:44:48

标签: c# .net generics reflection

我正在尝试通过反射调用泛型方法。我需要传递实现此方法期望参数的接口的类的对象。我收到System.ArgumentException告诉我“类型'ReflectionTest.MyRequest'的对象不能转换为类型'ReflectionTest.IRequest`1 [ReflectionTest.MyRequest]'”。

class Program
{
    static void Main(string[] args)
    {
        var request = new MyRequest();
        IMediator mediator = new Mediator();

        //This works (of course), but I need to call this by reflection. I don't know the type at design time.
        //var r = mediator.Send(request);

        //I tried this, but it doesn't work
        var type = request.GetType();
        var method = mediator.GetType().GetMethod("Send");
        var generic = method.MakeGenericMethod(type);
        //Exception
        var response = generic.Invoke(mediator, new object[] { request });

    }
}

public interface IRequest<out TResponse>
{

}

public interface IMediator
{
    TResponse Send<TResponse>(IRequest<TResponse> requests);
}

public class MyRequest : IRequest<MyResponse>
{
}

public class MyResponse
{
}

public class Mediator : IMediator
{
    public TResponse Send<TResponse>(IRequest<TResponse> requests)
    {
        Console.WriteLine("Processing...");
        return default(TResponse);
    }
}

有人问我在做什么错吗?不幸的是,我不太会思考,所以欢迎您提供帮助。

示例git repo:https://github.com/alan994/ReflectionProblem

3 个答案:

答案 0 :(得分:3)

在这一行:

var generic = method.MakeGenericMethod(type);

您正在创建type类型的通用方法,即MyRequest
因此,最终您将MyRequest用作TResponse

但是您实际上想要做的是将MyResponse传递为TResponse

您可以执行以下操作以便能够动态调用它:

  • 获取您正在执行的接口IMyRequest<>
  • 获取此接口的唯一通用参数,即TResponse

这是代码的外观,但是您需要在此处添加一些类型检查和有效的错误处理:

var type = request.GetType();

var responseType = type.GetInterfaces() // [IRequest<MyResponse>]
    .Single(i => i.GetGenericTypeDefinition() == typeof(IRequest<>)) // IRequest<MyResponse>
    .GetGenericArguments() // [MyResponse]
    .Single(); // MyResponse

var method = mediator.GetType().GetMethod("Send");
var generic = method.MakeGenericMethod(responseType); // note that responseType is used here

var response = generic.Invoke(mediator, new object[] { request });

毕竟,您确定要将响应绑定到请求的特定定义吗?我不知道您的体系结构以及您要实现的目标,但是,也许这可以是一个更加敏捷的解决方案:

public interface IRequest
{

}

public interface IMediator
{
    TResponse Send<TRequest, TResponse>(IRequest request);
}

public class MyRequest : IRequest
{
}

public class MyResponse
{
}

public class Mediator : IMediator
{
    public TResponse Send<TRequest, TResponse>(IRequest request)
    {
        Console.WriteLine("Processing...");
        return default(TResponse);
    }
}  

答案 1 :(得分:0)

您为Send方法的通用类型发送了错误的类型。它的通用类型是响应类型-TResponse,但您实际上将请求类型赋予了请求类型-IRequest<TResponse>

以下内容将为您提供正确的通用方法来调用。

var generic = method.MakeGenericMethod(typeof(MyReponse));

答案 2 :(得分:0)

问题在于您正在使用MyRequest而不是MyResponse来创建通用方法,请看一下签名Send<TResponse>。试试:

var generic = method.MakeGenericMethod(typeof(MyReponse));