views:

597

answers:

3
+4  Q: 

DLR return type

hi. I need some DLR help. I am implementing an IDynamicMetaObjectProvider and DynamicMetaObject but I am having some issues getting the expected return type. I am overiding BindInvokeMember in the metaobject, I can see all the args types but no return type. Anyone know how I get to it if possible? I know the return type is dynamic but what if the thing you are invoking is dependent on a return type. I don't know which action to perform in the DynamicMetaObject unless I know the return type the consumer is expecting.

Update Two

I cant paste my actual code here since it calls all kinds of work stuff. Some sample dynamic object code is below.

public class TestDynamicMetaObject : DynamicMetaObject
{
    public TestDynamicMetaObject(Expression expression, object value)
        : base (expression, BindingRestrictions.Empty, value)
    {
    }

    public override DynamicMetaObject BindInvokeMember(InvokeMemberBinder binder, DynamicMetaObject[] args)
    {
        Delegate method = new Func<int>(Test);
        return new DynamicMetaObject(
            Expression.Call(method.Method),
            BindingRestrictions.GetInstanceRestriction(Expression,Value),
            Value
        );
    }

    public static int Test()
    {
        return 10;
    }

}
public class TestDynamicObject : IDynamicMetaObjectProvider
{
    DynamicMetaObject IDynamicMetaObjectProvider.GetMetaObject(Expression parameter)
    {
        return new TestDynamicMetaObject(parameter, this);
    }
}

Here is where I am using.

static void Main(string[] args)
{
    try
    {
        dynamic x = new TestDynamicObject();
        int gg= x.Test();
        Console.WriteLine(gg);
    }
    catch (Exception excep)
    {
        Console.WriteLine(excep);
    }
    Console.ReadLine();
}

Here is the code that the compiler creates.

private static void Main(string[] args)
{
    try
    {
        object x = new TestDynamicObject();
        if (<Main>o__SiteContainer0.<>p__Site1 == null)
        {
            <Main>o__SiteContainer0.<>p__Site1 = CallSite<Func<CallSite, object, int>>.Create(new CSharpConvertBinder(typeof(int), CSharpConversionKind.ImplicitConversion, false));
        }
        if (<Main>o__SiteContainer0.<>p__Site2 == null)
        {
            <Main>o__SiteContainer0.<>p__Site2 = CallSite<Func<CallSite, object, object>>.Create(new CSharpInvokeMemberBinder(CSharpCallFlags.None, "Test", typeof(Program), null, new CSharpArgumentInfo[] { new CSharpArgumentInfo(CSharpArgumentInfoFlags.None, null) }));
        }
        Console.WriteLine(<Main>o__SiteContainer0.<>p__Site1.Target(<Main>o__SiteContainer0.<>p__Site1, <Main>o__SiteContainer0.<>p__Site2.Target(<Main>o__SiteContainer0.<>p__Site2, x)));
    }
    catch (Exception excep)
    {
        Console.WriteLine(excep);
    }
    Console.ReadLine();
}
+3  A: 

For the standard binaries which return something the return type is almost always object (get, set, operations, etc...). Otherwise it's void for the standard bindings (e.g. DeleteMember).

You can also get the expected return type at runtime from the ReturnType property on the incoming binder.

Dino Viehland
there is no return type on the incoming binder. Looks like methods called off dynamic objects always return a dynamic type hence object. The compiler generates some conversion code.
AbdElRaheim
What do you mean there is no return type on the incoming binder? If you mean there's no "ReturnType" property you have old sources. You can see this property clearly lives here:http://dlr.codeplex.com/SourceControl/changeset/view/27223#581318It is the DynamicMetaObject's responsibility to ensure that the type returned from the produced expression matches for standard binders.As for converting to dynamic - you don't need to convert to dynamic. Dynamic objects are always typed to object w/ extra metadata saying they are dynamic.
Dino Viehland
Yes I can see the property on codeplex. It does not exist in beta 1 bits I am using. I guess I will have to wait for the next vs2010 refresh.What i mean by conversion is the code below uses this will generate a convert as well. I remember reading somewhere that dynamic object method return objects and have to be converted. Is this not correct? The code generated by the compiler is in my post above. Has this changed also in the latest bits?object x = new DynamicTest();int w = x.Test();
AbdElRaheim
There shouldn't need to be any conversions. A dynamic object is just an object w/ an attribute saying it's dynamic. In the posted code it looks like you have a cast to int in the C# code. If the result of your InvokeMember is not an IDO then you'll never see the Convert call yourself - instead the C# binder will handle the conversion for normal .NET types. If that still doesn't answer the question you might want to post your C# code and your DynamicMetaObject implementation.
Dino Viehland
Not doing a cast myself. I updated the post to include the code. Again this vs2010 beta 1 so the behavior might have changed in the latest bits.
AbdElRaheim
also if I change the gg variable to object then the compiler doesnt generate any conversion code.
AbdElRaheim
If you change "Test" to returning a TestDynamicObject instead of an int then you will see the conversion request. Because you're returning a non-dynamic object here C# will just do it's normal conversion semantics. In this case the value is already an int so no conversion is necessary. If you returned a double instead then C# would do it's normal conversion from double to C#.
Dino Viehland
You could also just "return this;" from BindInvokeMember and then you'd see the convert happen as well.
Dino Viehland
going from an object to int is not normally conversion semantics. The other way around is :) So is there no way to see what type the consumer is expecting? The Test method is just a test method. What I am actually calling I pass in the expected return type as a parameter so I cannot make dynamic.
AbdElRaheim
When it's dynamic going from object (boxed int) to int IS normal conversion semantics. The only way you get to see the conversion is if the converted object is a dynamic object. If you absolutely need to see it just create a ConvertibleObject which is an IDynamicMetaObjectProvider that implements BindConvert. Then you can just wrap whatever value you return in your ConvertibleObject, you'll unbox the value and you'll see the conversion.
Dino Viehland
A: 

It appears the return type at least is the beta i was using is not know...

I was trying to make a p/invoke example using the DLR but it seems like this is not possible unless you pass in the expected return type as a parameter which I ended up doing :\ This seems to me like a limitation... Hopefully it will be addressed in the future.

Ziad
A: 

ReturnType property of InvokeMemberBinder always returns typeof(object) and the call site returns an object. The caller can convert that object to a specific type via a conversion site. ReturnType of the conversion site is the type the site converts to.

Why do you need to pass an expected return type as a parameter? Can you share the part of the binder that uses the type?

Tomas Matousek