Search code examples
c#objectdynamictryinvokemember

TryInvokeMember doesn't fire if binder name is GetType(), or ToString(), etc


I'm just messing around with the C# 4.0 dynamic keyword, and got curious about one thing.

Suppose I have a class DynamicWeirdness : DynamicObject

Inside it I have a field named reference which is also of type dynamic. And a field named referencetype which is of type Type

This is my constructor:

public DynamicWeirdness(object reference)
{
        this.reference = reference;
        this.referencetype = reference.GetType();
}

If I ever try this:

public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
    if (binder.Name == "GetType" && args.Length == 0)
    {
        result =  referencetype;
        return true;
    }
    result = null;
    return false;
}

When I call GetType() of a DynamicWeirdness object, it simply ignores my invocation and returns {Name = "DynamicWeirdness" FullName = "Dynamic1.DynamicWeirdness"}. Why?

I've tried with ToString(), GetHashCode(), and the same thing happens.


Solution

  • The methods GetType(), ToString(), and GetHashCode() are all defined on DynamicObject (since it inherits from System.Object). When .NET goes to invoke those methods, it will just call them directly since they are defined on the object, and will skip the call to TryInvokeMember.

    You can see this in action if you try calling a different method, like Substring(), and you'll see that TryInvokeMember on DynamicWeirdness does get called.

    Instead of overriding TryInvokeMember on DynamicWeirdness to return a different type, you can just create a new GetType() method on DynamicWeirdness.

    public new Type GetType()
    {
        return this.referencetype;
    }
    

    For GetHashCode() and ToString(), you can override those members on DynamicWeirdness since they are marked as virtual.