2015-04-02 5 views
1

У меня есть два процесса (A и B), оба имеют метод Foo (SomeClass paramA, SomeOtherClass paramB). процессы взаимодействуют с помощью Windows, Pipes (не WCF) и может отправлять и получать сообщения типа:C# Вызов метода с использованием отражения в общем виде

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; } 
} 

При вызове Foo на А, я хочу, чтобы вызвать Foo на В, с теми же значениями.

Это код вызова в A:

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

Это код ссылающееся в B:

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

Но как вы можете видеть, что я должен вручную создать список параметров для каждый звонок, поэтому, если я забуду параметр или неправильно сделаю заказ, все не сработает. Учитывая, что я не могу использовать отражение для получения значений, и я не хочу использовать профилировщик (производительность - это проблема), каков наилучший способ сделать его более общим?

Редактировать: я не могу использовать WCF по многим причинам (на самом деле, я ухожу от WCF). Я использую трубы, а именно PipeStream.

Edit2: Что я хочу - это решение, которое не полагается на ручное создание массивов параметров; то, что может создать этот массив автоматически для меня.

+0

hmm. вместо списка вы можете использовать словарь и поместить имя параметра в ключ? – Ewan

+0

Но на самом деле я хотел бы сделать это _less_ generic и создать некоторый строго типизированный метод связи. не знаете, сколько вы можете изменить? – Ewan

+0

Да, я знаю, что могу преодолеть проблему заказа, то, что я действительно хочу, является чем-то более общим - что-то, что позволит мне вручную объявить набор значений. – Tsury

ответ

0

В итоге я использовал RealProxy. RealProxy в основном используется для удаленного доступа, но может позволить вам создавать прокси для классов. Затем вы можете добавить функциональность перед каждым вызовом метода (также вызовы свойств). Я использовал это очень хорошо blog post для его реализации.

Это мой прокси:

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_MethodCall.InArgs, чтобы получить в-аргументы, что это слышат вопроса. Также обратите внимание, как HandleMethodCall использует этот канал, чтобы вытолкнуть сообщение вместо фактического вызова запрошенного метода. Это означает, что мой класс «API» на самом деле просто пустые методы, не имеющие реализаций (я всегда могу добавить больше реализации там и вызвать метод до/после действия трубы):

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

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

Кроме того, как требование RealProxy , класс должен унаследовать от MarshalByRefObject, который был прекрасен мной, поскольку он не имеет других функций. Подробнее об этом читайте в сообщении в блоге, которое я связал.

Смежные вопросы