Search code examples
c#reflectionexpression-trees

Why does the evaluation of Expression.TypeAs return an object of the underlying concrete type and not the interface I've requested it to?


The actual answer is in the comments on the answer. I was expecting to get an 'instance' of my interface, which you can't do.

--

I found a way to do what I actually wanted, which for anyone interested, I've outlined below.

public interface Interface<T> { Func<T,T> Property { get; set; } }

public class Concrete : Interface<string>
{
    public Concrete()
    {
        (this as Interface<string>).Property = (s) => { return $"hello, {s}!"; };
    }

    Func<string, string> Interface<string>.Property
    {
        get;
        set;
    }
}

class Program
{
    static void Main(string[] args)
    {
        object obj = new Concrete();

        var propInfo = obj.GetType().GetInterfaces().Single().GetProperty("Property");

        dynamic func = propInfo.GetMethod.Invoke(obj, null);

        var output = func("world");
    }        
}

--

I'm doing some codegen and am making heavy use of dynamic types and unfortunately I've hit the dynamic type/explicit interface conundrum.

I can get around this by using Convert.ChangeType(...) as outlined here but it requires that IConvertable is implemented which will have a large overhead that I don't want to have to do.

I've found an example of using Linq expressions to do this using either Expression.TypeAs or Expression.Convert, however this always returns the underlying concrete type and not the interface I need.

Here's a code example of what I'm trying to do:

namespace ExpressionCasting
{
   public interface Interface<T> { void Method(T t); }

   public class ImplementedInterface : Interface<string> 
   { 
      void Interface<string>.Method(string t) { } 
   }

   class Program 
   { 
      static void Main(string[] args)
      {
          var implementedInterface = new ImplementedInterface();      

          // type is an IInterface<string>
          var type = implementedInterface.GetType().GetInterfaces().Single(); 

          // i is always an ImplementedInterface
          var i = Convert(type, implementedInterface); // i is always an ImplementedInterface

          Console.WriteLine(i.GetType()); // i want this to be an IInterface<string> nit and ImplementedInterface. 
      }

      static object Convert(Type type, object subClass)
      {
         var body = Expression.TypeAs(
            Expression.Constant(subClass, subClass.GetType()), type);

         var run = Expression.Lambda(
            body, Expression.Parameter(subClass.GetType())).Compile();

         return run.DynamicInvoke(subClass);
      }
   }
}

Any ideas how I can get what I need with expressions or if there is another option I haven't thought of?


Solution

  • The issue isn't with your expression. It's with the use of dynamic. The DLR isn't looking at explicit interface implementations. It's easy to prove since the following code returns the same exception:

    dynamic i = new ImplementedInterface();
    i.Method(); // throws exception as method is not found.
    

    Here is a small article on the issue as well as other surprises when using dynamic: http://csharpindepth.com/Articles/Chapter14/DynamicGotchas.aspx