ekonbenefits / impromptu-interface

Static interface to dynamic implementation (duck casting). Uses the DLR combined with Reflect.Emit.
Apache License 2.0
655 stars 67 forks source link

Incorrect binder.ReturnType #40

Open nesteruk opened 3 years ago

nesteruk commented 3 years ago

Say we define a null object like this:

  public class Null<T> : DynamicObject where T:class
  {
    public static T Instance
    {
      get
      {
        if (!typeof(T).IsInterface)
          throw new ArgumentException("I must be an interface type");

        return new Null<T>().ActLike<T>();
      }
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, 
      object[] args, out object result)
    {
      result = Activator.CreateInstance(binder.ReturnType);
      return true;
    }
  }

And an interface like this

public interface ILog
{
  void Info(string msg);
  bool Warn(string msg);
}

Calling Null<ILog>.Instance.Warn("...") gives an exception because in TryInvokeMember, the value of binder.ReturnType is System.Object for some reason. Looks like ImpromptuInterface is failing to specify binder.ReturnType correctly on the basis of what the members actually are. binder.Name is correct, though.

teneko commented 3 years ago

As of my understanding, the ReturnType will always be object. After the method e.g. TryInvokeMember has processed, the ReturnType will be evaluated from the result you just set in TryInvokeMember. I think that's called dynamic. :^

Just imagine you would create a derived type of DynamicObject and provoke TryInvokeMember with e.g. dynObj.getNumber(5). Do you know what the return type will be before you call it? You as implementer of TryInvokeMember, maybe. Another view is that you are deciding of which type the result will be by setting it after evaluating argument list, method name and so on.