tags:

views:

174

answers:

3

I'm writing a simple wrapper to "duck" a dynamic object against a known interface:

interface IFoo { string Bar(int fred); }

class DuckFoo : IFoo
{
    private readonly dynamic duck;

    public DuckFoo(dynamic duck)
    {
        this.duck = duck;
    }

    public string Bar(int fred)
    {
        return duck.Bar(fred);
    }
}

This works fine if the dynamic object can respond to the Bar signature. But if it cannot this fails only when I call Bar. I would prefer if it could fail faster, i.e., with argument validation upon construction of the DuckFoo wrapper. Something like this:

public DuckFoo(dynamic duck)
{
    if(/* duck has no matching Bar method */)
        throw new ArgumentException("duck", "Bad dynamic object");
    this.duck = duck;
}

In Ruby there is a respond_to? method that can be used to test if an object "has" a certain method. Is there a way to test that with dynamic objects in C# 4?

(I am aware that even with this check the Bar call could fail later on because the dynamic nature of the duck lets it stop responding to methods later on.)

+3  A: 

You could check the methods available on the object being wrapped using Reflection, at construction time.

Just call Type.GetMethods() on the interface and the type being passed in, and make sure the appropriate methods exist.


Edit:

As suggested by itowlson, there is an option for handling dynamic types, as well. If you check for the existance of the IDynamicMetaObjectProvider interface on the passed object, you could then call IDynamicMetaObjectProvider.GetMetaObject().GetDynamicMemberNames(), and use this information.

If the interface does not exist, you could just revert to Type.GetMethods().

This should handle the "dynamic" types, as well.

Reed Copsey
What happens when you do `duck.GetType()` if `duck` is declared as `dynamic duck`? What type does it return?
dtb
If the dynamic object is a .NET object, you get the Type of the object.
Maximilian Mayerl
I don't think you can do reflection like that on dynamic objects... Maybe if they are regular CLR objects you can, but you can't with objects coming from IronRuby, for example...
Martinho Fernandes
This will work for CLR objects. If you're dealing with a type coming from a completely dynamic language, the language may have its own mechanisms for that. However, it's difficult (very tricky) to provide type safety on top of, by definition, untyped objects. If you're dealing with a truly untyped object, then you should use that language's mechanisms for type dispatching, or leave it as a runtime check.
Reed Copsey
@dtb: like Maximilian said, if it is a regular CLR object treated as dynamic, you get the Type of the object. But if comes from a dynamic language, it will be something along the lines of `IronRubyDynamicObject` or `IronPythonDynamicObject` (nb: I made these names up, I don't know the actual names)
Martinho Fernandes
Yeah - I know. If it's a dynamic object, though, I personally would leave it dynamic. There is no way to know that a method won't be removed between the time you construct and the time you call, for example. In that case, runtime fails make the most sense.
Reed Copsey
You could combine the static GetMethods() with a test for IDynamicMetaObjectProvider and a call to IDynamicMetaObjectProvider.GetMetaObject().GetDynamicMemberNames().
itowlson
Note that there are some standardized mechanisms for dynamic objects in .NET 4 (e.g. `ExpandoObject`), so it's not always language-specific even for true dynamic objects.
Pavel Minaev
@itowlson: Good call. I edited my answer to include that.
Reed Copsey
@Pavel: Good call. Totally forgot that! @itowlson: That's more like what I wanted.
Martinho Fernandes
A: 

Use reflection to check for methods:

if (duck.GetType().GetMethod("Bar") == null) {
    throw new ArgumentException("duck", "Bad dynamic object");
}
Jon Benedicto
That works, but only with regular CLR objects. Truly dynamic objects might not have a Bar method and still respond to the call.
Martinho Fernandes
+1  A: 

I don't know of a definite way to check if the object provides a specific method. Of course, you could use reflection, but that only works if the object is a .NET object. If you are sure that it is, than, as already said, no problem, just call GetType() on the object and check with GetMethod().

On the other hand, as you said yourself, even a check at this point doesn't guarentee that the call to the method will succeed later on, so I think that the check is useless. Just let the call fail when it actually does. It could also be that your check says the object doesn't provide a specific method, but later on, when you would actually call it, it does.

Maximilian Mayerl