4
\$\begingroup\$

Sometimes when working with components created by a library vendor such as DevExpress you want to extend the components. Good vendors will leave plenty of virtual methods for you to put to use, but once in a while you need to hook into an interface method call in a class that implements the method explicitly. You can simply reimplement the interface method, but nine times out of ten you will still want to call the base implementation as though it were virtual. As a matter of fact, it should have been virtual (CA1033).

In the meantime, the base implementation is private and you need to use reflection. This class mitigates some of that nuisance so that you don't have to hand-roll reflection code. It hands you an object implementing the interface that calls directly into the private base implementation methods.

An example is worth a thousand explanations:

interface IExampleInterface
{
 string InterfaceMethod();
}
class BaseClass : IExampleInterface
{
 // The authors of BaseClass did not follow CA1033: Interface methods should be callable by child types
 string IExampleInterface.InterfaceMethod()
 {
 return "BaseClass implementation";
 }
}
sealed class CustomizedClass : BaseClass, IExampleInterface
{
 // We have no choice but to override by implementing the method.
 string IExampleInterface.InterfaceMethod()
 {
 // Now in order to access the base explicit implementation, we use the class below:
 return LanguageUtils.ExplicitImplementation<BaseClass, IExampleInterface>(this).InterfaceMethod() + " has been customized.";
 }
}

Surprisingly, there's barely any code:

public static class LanguageUtils
{
 public static TInterface ExplicitImplementation<TBase, TInterface>(TBase @this)
 where TBase : TInterface
 where TInterface : class
 {
 return (TInterface)new ExplicitImplementationProxy(typeof(TBase), @this).GetTransparentProxy();
 }
 private sealed class ExplicitImplementationProxy : RealProxy, IRemotingTypeInfo
 {
 private readonly Type baseType;
 private readonly object instance;
 public ExplicitImplementationProxy(Type baseType, object instance) : base(typeof(MarshalByRefObject))
 {
 this.baseType = baseType;
 this.instance = instance;
 }
 public bool CanCastTo(Type fromType, object o)
 {
 return fromType.IsInterface && fromType.IsAssignableFrom(baseType);
 }
 public string TypeName { get; set; }
 public override IMessage Invoke(IMessage msg)
 {
 var methodCall = msg as IMethodCallMessage;
 if (methodCall == null) throw new NotSupportedException();
 var map = baseType.GetInterfaceMap(methodCall.MethodBase.DeclaringType);
 var args = new object[methodCall.Args.Length];
 Array.Copy(methodCall.Args, args, args.Length);
 return new ReturnMessage(map.TargetMethods[Array.IndexOf(map.InterfaceMethods, (MethodInfo)methodCall.MethodBase)].Invoke(instance, args), args, args.Length, methodCall.LogicalCallContext, methodCall);
 }
 }
}
asked Jun 18, 2015 at 12:21
\$\endgroup\$
5
  • 1
    \$\begingroup\$ there isn't a whole lot of explanation here, except for the title???? could you add something more to this? \$\endgroup\$ Commented Jun 18, 2015 at 13:06
  • \$\begingroup\$ string IExampleInterface.InterfaceMethod() Is this BaseClass implementation not private? private == not inherited. \$\endgroup\$ Commented Jun 18, 2015 at 20:34
  • 1
    \$\begingroup\$ @Lyle'sMug is that better? \$\endgroup\$ Commented Jun 19, 2015 at 12:35
  • \$\begingroup\$ @radarbob That is correct. That's what this is about- calling private interface implementations when the base class is violating CA1033. \$\endgroup\$ Commented Jun 19, 2015 at 12:37
  • \$\begingroup\$ That is much better \$\endgroup\$ Commented Jun 19, 2015 at 13:07

1 Answer 1

2
\$\begingroup\$

This is a pretty tidy implementation, not much to say here. A couple very minors:

  1. This is a bit hard to read:

    return new ReturnMessage(.Invoke(instance, args), args, args.Length, methodCall.LogicalCallContext, methodCall);
    

    I'd split it up:

    var targetMethod = map.TargetMethods[Array.IndexOf(map.InterfaceMethods, (MethodInfo)methodCall.MethodBase)];
    return new ReturnMessage(targetMethod.Invoke(instance, args), args, args.Length, methodCall.LogicalCallContext, methodCall);
    
  2. Clone the argument array instead of explicitly copying it:

    var args = (object[])methodCall.Args.Clone();
    

    Expresses the semantics on a more compact way.

  3. For me this seems to be some sort of method forwarding so I'd possibly consider renaming it and maybe turning it into an extension method (I like the syntactic sugar of it). Something along these lines:

    public static TInterface ForwardToBase<TBase, TInterface>(this TBase @this)
     where TBase : TInterface
     where TInterface : class
    {
     return (TInterface)new ExplicitImplementationProxy(typeof(TBase), @this).GetTransparentProxy();
    }
    

    In which case the call would then read as:

    this.ForwardToBase<BaseClass, IExampleInterface>().InterfaceMethod()
    
answered Nov 5, 2015 at 19:37
\$\endgroup\$
1
  • \$\begingroup\$ I like it. I considered #3, but I didn't want it showing up in intellisense for every object since it shouldn't be a common necessity. Maye if we had an interface constraint. \$\endgroup\$ Commented Nov 5, 2015 at 19:56

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.