调用从封闭泛型继承的methodinfo

时间:2015-08-21 05:47:09

标签: c# generics reflection

 private static void Main(string[] args)
    {
        var messageType = typeof (SampleHandler1);
        var genericType = typeof (IConsume<>).MakeGenericType(messageType);
        var genericArguments = genericType.GetGenericArguments();
        var consumeMethod = genericType.GetMethod("Consume");

        var constructorInfo = genericArguments[0].GetConstructor(Type.EmptyTypes);
        var classObject = constructorInfo.Invoke(new object[] {});

        var argsx = new object[] {new SampleMessage {Name = "sample message"}};

        consumeMethod.Invoke(classObject, argsx);
    }

public interface IConsume<in T> where T : class
{
    void Consume(T message);
}

public class SampleHandler1 : IConsume<SampleMessage>
{
    public SampleHandler1()
    {
        Debugger.Break();
    }

    public void Consume(SampleMessage message)
    {
        Debugger.Break();
        Console.WriteLine("Message consume: " + message.Name);
    }
}


public interface IBaseMessage
{
}

public class SampleMessage : IBaseMessage
{
    public string Name { get; set; }
}

我试过看这里,但我找不到具体的解决方案。正如MSDN解释

  

OBJ   键入:System.Object   要调用方法或构造函数的对象。如果方法是静态的,则忽略此参数。如果构造函数是静态的,则此参数必须为null或定义构造函数的类的实例。

classObject是构造函数的一个实例,对吗?为什么会引发异常:enter image description here

2 个答案:

答案 0 :(得分:4)

这似乎不对。让我们分析一下这里发生了什么:

var messageType = typeof (SampleHandler1);
//simple enough, Type -> SampleHandler1

var genericType = typeof (IConsume<>).MakeGenericType(messageType);
//so genericType is a Type -> IConsume<SampleHandler1>

var genericArguments = genericType.GetGenericArguments();
//there's only one, but Type[] { Type -> SampleHandler1 }

var consumeMethod = genericType.GetMethod("Consume");
//MethodInfo -> IConsume<SampleHandler1>.Consume(SampleHandler1)

var constructorInfo = genericArguments[0].GetConstructor(Type.EmptyTypes);
//ConstructorInfo -> SampleHandler1..ctor()

var classObject = constructorInfo.Invoke(new object[] {});
//new SampleHandler1()

var argsx = new object[] {new SampleMessage {Name = "sample message"}};
//object[] { SampleMessage }

consumeMethod.Invoke(classObject, argsx);
//((IConsume<SampleHandler1>)classObject).Consume( SampleMessage ) -- oops?

所以classObjectSampleHandler1,但您正在尝试调用IConsume<SampleHandler1>.Consume(SampleHandler1),更糟糕的是,它会以SampleMessage作为参数。

我认为您打算创建一个SampleHandler1,并在其上调用IConsume<SampleMessage>.Consume(SampleMessage)

var messageType = typeof(SampleMessage);
var genericType = typeof(IConsume<>).MakeGenericType(messageType);
var consumeMethod = genericType.GetMethod("Consume");

var handlerType = typeof(SampleHandler1);
var constructorInfo = handlerType.GetConstructor(Type.EmptyTypes);
var classObject = constructorInfo.Invoke(new object[] {});

var argsx = new object[] {new SampleMessage {Name = "sample message"}};

consumeMethod.Invoke(classObject, argsx);

答案 1 :(得分:0)

我不确定,但根据你问题中的所有组件,我怀疑你正在寻找更像这样的东西:

使用System;

public class Program
{
    public static void Main()
    {
        var handlerType = typeof (SampleHandler1);
        var genericType = handlerType.GetInterface("IConsume`1");
        var genericArguments = genericType.GetGenericArguments();
        var consumeMethod = genericType.GetMethod("Consume");

        var handlerConstructorInfo = handlerType.GetConstructor(Type.EmptyTypes);
        var handler = handlerConstructorInfo.Invoke(new object[] {});

        var messageConstructorInfo = genericArguments[0].GetConstructor(Type.EmptyTypes);
        var messageObject = messageConstructorInfo.Invoke(new object[] {});

        ((IBaseMessage)messageObject).Name = "Sample Message";

        var argsx = new object[] {messageObject};

        consumeMethod.Invoke(handler, argsx);

    }
}

public interface IConsume<in T> where T : class, IBaseMessage
{
    void Consume(T message);
}

public class SampleHandler1 : IConsume<SampleMessage>
{
    public SampleHandler1()
    {
        Console.WriteLine("SampleHandler1 constructed");
    }

    public void Consume(SampleMessage message)
    {
        Console.WriteLine("Message consume: " + message.Name);
    }
}


public interface IBaseMessage
{
    string Name { get; set; }
}

public class SampleMessage : IBaseMessage
{
    public string Name { get; set; }
}

这是上述答案的一个有效的Dotnetfiddle:https://dotnetfiddle.net/YFmmzk

控制台输出是:

  

构建SampleHandler1

     

消息使用:示例消息

看起来你的处理程序和消息类型混淆了。您试图将处理程序本身的实例传递给consume方法。更重要的是,IBaseMessage缺少Name属性声明。

<强>更新

以下是此答案的cleaned版本:

public class Program
{
    public static void Main()
    {
        var handler = new DynamicConstructor(typeof (SampleHandler1)).New();
        invokeIConsumeFor(handler, "Sample Message");
    }

    private static void invokeIConsumeFor(object handler, string message)
    {
        var executer      = new DynamicGenericInterfaceExecuter(handler, "IConsume`1");
        var messageObject = executer.GetTypeArgumentConstructor(0, Type.EmptyTypes).New();

        ((IBaseMessage) messageObject).Name = message;

        executer.Method("Consume", messageObject.GetType()).Call(messageObject);
    }
}

public class DynamicGenericInterfaceExecuter
{
    private object instance;
    private Type genericInterfaceFromType;
    private Type[] genericTypeArguments;

    public DynamicGenericInterfaceExecuter(object instance, string interfaceName)
    {
        this.instance                 = instance;
        this.genericInterfaceFromType = instance.GetType().GetInterface(interfaceName);
        this.genericTypeArguments     = this.genericInterfaceFromType.GetGenericArguments();
    }

    public MethodExecuter Method(string methodName, params Type[] parameterTypes)
    {
        return new MethodExecuter(this.instance, this.genericInterfaceFromType, methodName, parameterTypes);
    }

    public DynamicConstructor GetTypeArgumentConstructor(int typeArgumentIndex, params Type[] constructorParameterTypes)
    {
        return new DynamicConstructor(this.genericTypeArguments[typeArgumentIndex], constructorParameterTypes);
    }
}

public class DynamicConstructor
{
    private System.Reflection.ConstructorInfo constructor;

    public DynamicConstructor(Type type, params Type[] constructorParameters)
    {
        this.constructor = type.GetConstructor(constructorParameters);
    }

    public object New(params object[] constructorArguments)
    {
        return this.constructor.Invoke(constructorArguments);
    }
}

public class MethodExecuter
{
    private object instance;
    private System.Reflection.MethodInfo method;

    public MethodExecuter(object instance, Type containerType, string methodName, Type[] methodParameters)
    {
        this.instance = instance;
        this.method   = containerType.GetMethod(methodName, methodParameters);
    }

    public void Call(params object[] arguments)
    {
        this.Invoke(arguments);
    }

    public object Invoke(params object[] arguments)
    {
        return this.method.Invoke(instance, arguments);
    }
}

public interface IConsume<in T> where T : class, IBaseMessage
{
    void Consume(T message);
}

public class SampleHandler1 : IConsume<SampleMessage>
{
    public SampleHandler1()
    {
        Console.WriteLine("SampleHandler1 constructed");
    }

    public void Consume(SampleMessage message)
    {
        Console.WriteLine("Message consume: " + message.Name);
    }
}

public interface IBaseMessage
{
    string Name { get; set; }
}

public class SampleMessage : IBaseMessage
{
    public string Name { get; set; }
}

dotnetfiddle:https://dotnetfiddle.net/n9WHZ2

请记住,这不是最安全的类型,但在您的问题中似乎不是一个问题。