5

I'm trying to handle a call of a generic method through a RealProxy, but I cannot seem to find the information about the actual type of the generic parameter used in the intercepted method call. An excerpt of the code:

    public override IMessage Invoke(IMessage msg)
    {
        ...
        string methodName = (string)msg.Properties["__MethodName"];
        Type[] parameterTypes = (Type[])msg.Properties["__MethodSignature"];
        object[] args = (object[])msg.Properties["__Args"];

        MethodInfo method = typeToProxy.GetMethod(methodName, parameterTypes);
        ...

Let's say I'm proxying an interface like

interface IFactory
{
   TService Create<TService>()
}

When I call the proxy

proxied.Create<MyClass>()

I want to be able to find out the generic parameter is of type MyClass. Is this possible through RealProxy?

Igor Brejc
  • 18,714
  • 13
  • 76
  • 95
  • It is possible through reflection to query for generic types. – fhj Oct 31 '10 at 08:27
  • Trying to find out the exact generic class somewhat defeats the purpose of having a generic class. Why do you need to know the class? – Albin Sunnanbo Oct 31 '10 at 09:02
  • @Albin, I'm writing a factory method proxy for a dependency injection framework I'm working on. Something like Windsor's typed factory facility (http://kozmic.pl/archive/2009/12/24/castle-typed-factory-facility-reborn.aspx) – Igor Brejc Oct 31 '10 at 13:41

2 Answers2

6

There is an excellent MSDN article about RealProxy which I recommend you read. Among other things, it introduces MethodCallMessageWrapper which saves you the trouble of working directly against the Properties dictionary. From the latter you can get the MethodBase, which in turn contains the generic arguments:

internal class MyProxy : RealProxy
{
   private object m_instance;    
   private MyProxy( object instance ) : base( typeof( IFactory) )
   {
      m_instance = instance;
   }

  public override IMessage Invoke( IMessage message )
  {
     IMethodCallMessage methodMessage =
        new MethodCallMessageWrapper( (IMethodCallMessage) message );

     // Obtain the actual method definition that is being called.
     MethodBase method = methodMessage.MethodBase;

     Type[] genericArgs = method.GetGenericArguments(); //This is what you want

     return new ReturnMessage(...);
  }

  ...
}
Ohad Schneider
  • 36,600
  • 15
  • 168
  • 198
3

For method calls, the IMessage argument should be a IMethodMessage, which has a MethodBase property:

public override IMessage Invoke(IMessage message)
{
    IMethodMessage methodMessage = message as IMethodMessage;
    if (methodMessage != null)
    {
         MethodBase method = methodMessage.MethodBase;
         Type[] genericArgs = method.GetGenericArguments();

         ...
    }
    else
    {
        // not a method call
    }
}
Ruben
  • 15,217
  • 2
  • 35
  • 45
  • Ruben, I tested your code and it works, thanks, +1. I'm sorry I could not accept both answers. – Igor Brejc Oct 31 '10 at 13:39
  • 1
    Since `IMethodCallMessage` implements `IMethodMessage`, and `MethodCallMessageWrapper` is a simple wrapper for `IMethodCallMessage`, both our answers boil down to pretty much the same code – Ohad Schneider Oct 31 '10 at 14:18