Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this method keep returning dynamic despite the return type in the signature?

Tags:

c#

.net

dynamic

So the type being returned by the activator (not shown here) is just a POCO that I created. Nothing special about it at all. But despite, the return type of GetWrapper or GetWrapper<T> the object being returned is of type dynamic so none of the properties of the actual class being return are being seen by intellisense. Any ideas?

enter image description here

UPDATE: Sorry, Jon:

public static T GetWrapper<T>(object type, dynamic obj)
   where T : class, IRedditObject
{
    return GetWrapper(type, obj) as T;
}

public static object GetWrapper(object type, dynamic obj)
{
    return Activator.CreateInstance(Types[type.ToString()], obj);
}

public class LinkWrapper : IRedditObject
{
    private readonly dynamic _link;

    public string Kind { get { return "t3"; } }
    public dynamic Data { get { return _link.data; } }

    public LinkWrapper(dynamic link)
    {
        _link = link;
    }

    public string Domain { get { return Data.domain; } }
}

[TestMethod]
public void Test()
{
    var proxy = new SubredditProxy();
    var dotnet = proxy.GetSubredditAsync("dotnet").Result;

    var child1 = dotnet.data.children[0];

    // this is being returned as dynamic
    var obj = RedditDynamicObjectWrapperFactory.GetWrapper<LinkWrapper>(child1.kind, child1);


    Assert.IsNotNull(obj);
}
like image 349
Sinaesthetic Avatar asked Sep 13 '25 20:09

Sinaesthetic


1 Answers

I strongly suspect that either child1 or child1.kind are of type dynamic, meaning that the expression is deemed to be a dynamically-bound expression, despite everything else.

Here's a short but complete example to demonstrate what I mean:

using System;

class Test
{
    public static T Foo<T>(object x)
    {
       return default(T);
    }

    public static void Main(string[] args)
    {
        object a = new object();
        dynamic b = a;

        var c = Foo<string>(a);
        var d = Foo<string>(b);

        Console.WriteLine(c.SomeRandomMember); // Invalid
        Console.WriteLine(d.SomeRandomMember); // Valid
    }
}

The invalid statement is invalid because the type of c is string - but the subsequent statement is fine, because the type of d is dynamic.

Even though there's only one possible method which it could be bound to at execution time - and even though that binding will always work - the basic rule is that almost any expression involving a dynamic value is deemed to be of type dynamic. (There are a few exceptions such as as and new.)

To make your return value non-dynamic, just cast your values to object:

var obj = RedditDynamicObjectWrapperFactory.GetWrapper<LinkWrapper>
     ((object) child1.kind, (object) child1);

That will now be a statically bound call. Or you could leave it as a dynamically bound call, and use the implicit conversion from an expression of type dynamic to other types:

LinkWrapper obj = RedditDynamicObjectWrapperFactory.GetWrapper<LinkWrapper>(child1.kind, child1);
like image 120
Jon Skeet Avatar answered Sep 16 '25 10:09

Jon Skeet