简体   繁体   English

C#以一般方式调用使用反射的方法

[英]C# Invoking a method using reflection in a generic manner

I have two processes (A and B), both have a method Foo(SomeClass paramA, SomeOtherClass paramB). 我有两个过程(A和B),都有一个方法Foo(SomeClass paramA,SomeOtherClass paramB)。 The processes communicate using Windows Pipes (not WCF) and can send and receive messages of type: 进程使用Windows管道(不是WCF)进行通信,并且可以发送和接收以下类型的消息:

public class PipeMessageArgs
{
     public PipeMessageArgs(string i_MethodName, List<object> i_Args)
      {
          MethodName = i_MethodName;
          Args = i_Args;
      }

      public string MethodName { get; private set; }
      public List<object> Args { get; private set; }
}

When calling Foo on A, I want to invoke Foo on B, with the same values. 在A上调用Foo时,我想以相同的值在B上调用Foo。

This is the calling code in A: 这是A中的调用代码:

public void Foo(SomeClass paramA, SomeOtherClass paramB)
{
    var args = new List<object> { paramA, paramB };
    m_Server.PushMessage(new PipeMessageArgs(MethodBase.GetCurrentMethod().Name, args));
}

This is the invoking code in B: 这是B中的调用代码:

void ClientOnReceiveMessage(NamedPipeConnection i_Connection, object i_Message)
{
    var pipeMessageArgs = i_Message as PipeMessageArgs;
    GetType().GetMethod(pipeMessageArgs.MethodName).Invoke(this, pipeMessageArgs.Args.ToArray());
}

But as you can see, I have to manually create a list of parameters for each call so if I forget a parameter or get the order wrong, things will not work. 但是如您所见,我必须为每个调用手动创建参数列表,因此,如果我忘记了一个参数或弄错了顺序,将无法正常工作。 Given that I cannot use reflection to get the values, and I do not want to use the profiler (performance is an issue), what is the best way to make it more generic? 鉴于我无法使用反射来获取值,并且我不想使用分析器(性能是一个问题),使它更通用的最佳方法是什么?

Edit: I cannot use WCF for too many reasons (actually, I am moving away from WCF). 编辑:由于太多原因,我无法使用WCF(实际上,我正在远离WCF)。 I am using pipes, namely PipeStream. 我正在使用管道,即PipeStream。

Edit2: What I want is a solution that does not rely on manually creating arrays of parameters; Edit2:我想要的是一个不依赖于手动创建参数数组的解决方案。 something that can create this array automatically for me. 可以自动为我创建此数组的东西。

I ended up using RealProxy . 我最终使用了RealProxy RealProxy is mainly used for remoting but can allow you to create proxy for classes. RealProxy主要用于远程处理,但可以让您创建类的代理。 You can then add functionality before each method call (also properties calls). 然后,您可以在每个方法调用(也包括属性调用)之前添加功能。 I used this very nice blog post to implement it. 我用这篇非常不错的博客文章来实现它。

This is my proxy: 这是我的代理:

public class InvokingProxy : RealProxy
    {
        private readonly INamedPipe _namedPipe;

        InvokingProxy(object i_Target, INamedPipe i_NamedPipe) : base(i_Target.GetType())
        {
            _namedPipe = i_NamedPipe;
        }

        public override IMessage Invoke(IMessage i_Msg)
        {
            var methodCall = i_Msg as IMethodCallMessage;

            if (methodCall != null)
            {
                return HandleMethodCall(methodCall);
            }

            return null;
        }

        IMessage HandleMethodCall(IMethodCallMessage i_MethodCall)
        {
            _namedPipe.PushMessage(new PipeMessageArgs(i_MethodCall.MethodName, i_MethodCall.InArgs));
            return new ReturnMessage(null, null, 0, i_MethodCall.LogicalCallContext, i_MethodCall);
        }

        public static T Wrap<T>(T i_Target, INamedPipe i_NamedPipe) where T : MarshalByRefObject
        {
            return (T)new InvokingProxy(i_Target, i_NamedPipe).GetTransparentProxy();
        }
    }

I use i_MethodCall.InArgs to get the in-arguments, that's the hear of the issue. 我使用i_MethodCall.InArgs来获取参数,这就是问题所在。 Also notice how HandleMethodCall uses the pipe to push a message instead of actually calling the requested method. 还要注意HandleMethodCall如何使用管道推送消息,而不是实际调用请求的方法。 This means that my 'API' class is actually just empty methods with no implementation (I can always add more implementation there and invoke the method before/after the pipe action): 这意味着我的“ API”类实际上只是没有实现的空方法(我可以随时在其中添加更多实现,并在管道操作之前/之后调用该方法):

class Api : MarshalByRefObject, IApi
    {
        public void Foo(SomeClass paramA, SomeOtherClass paramB)
        {
        }

        public void Bar(SomeClassX paramA, SomeOtherClassY paramB)
        {
        }
    }
}

Also, as a requirement of RealProxy. 另外,作为RealProxy的要求。 the class has to inherit from MarshalByRefObject which was fine by me as it has no other functionality. 该类必须继承自MarshalByRefObject,这对我来说很好,因为它没有其他功能。 Read more about it in the blog post I linked. 在我链接的博客文章中了解有关它的更多信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM