Seb Nilsson
Seb Nilsson

Reputation: 26408

Complex anonymous objects to dynamic public properties

How do I make the complex structure of an anonymous object public inside a dynamic object?

Anonymous objects are flagged as internal, so I'm looking for a creative way to work around this.

// This is the library I control
public void SendObject() {
    var anonymous = new {
        Text = "Test",
        SubItem = new {
            SubText = "Bla",
            SubSub = new {
                SubSubText = "Baha"
            }
        }
    };
}

dynamic dyn = ExposeAnonymous(anonymous); // Perform voodoo

var result = ExternalLibrary.GetSpecialProperty(dyn);

// External library I don't control
public object GetSpecialProperty(dynamic dyn) {
    return dyn.SubItem.SubSub.SubSubText;
}

The problem is when sending the dynamic to other external libraries, that I don't control, you get an error like:

'object' does not contain a definition for 'SubItem'.

Upvotes: 1

Views: 2316

Answers (3)

jbtule
jbtule

Reputation: 31799

With my opensource framework ImpromptuInterface (in nuget) you can create complex expando graphs with an inline syntax.

dynamic New = Builder.New<ExpandoObject>();

dynamic dyn = New.Obj(
        Text: "Test",
        SubItem: New.Obj(
            SubText: "Bla",
            SubSub: New.Obj(
                SubSubText: "Baha"
            )
        )
    );

Upvotes: 1

Mike Zboray
Mike Zboray

Reputation: 40818

Anonymous types are internal and the DLR does the same accessibility analysis at run-time that the compiler does at compile-time. So you cannot access the anonymous type's members from another assembly using dynamic.

One option might be to use ExpandoObject:

        dynamic a = new ExpandoObject();
        a.Text = "Test";
        a.SubItem = new ExpandoObject();
        a.SubItem.SubText = "Blah";
        a.SubItem.SubSub = new ExpandoObject();
        a.SubItem.SubSub.Text = "Baha";

This is kind of ugly so, you could keep the anonymous type and use a helper method to recursively convert to an ExpandoObject:

    public static dynamic ConvertToExpando(object obj)
    {
        IDictionary<string, object> expando = new ExpandoObject();
            foreach(var pi in obj.GetType().GetProperties())
            {
                // there doesn't seem to be a way to know if it is an anonymous type directly. So I use IsPublic here.
                if (pi.PropertyType.IsPublic)
                {
                    expando[pi.Name] = pi.GetValue(obj);                    
                }
                else
                {
                    expando[pi.Name] = ConvertToExpando(pi.GetValue(obj));
                }
            }
        return expando;
    }

This does the "Perform voodoo" that you need.

Upvotes: 5

Jon Skeet
Jon Skeet

Reputation: 1500505

The problem is when sending the dynamic to other libraries,

... And there's the rub. Anonymous types are declared as internal by the C# compiler, which means that other assemblies don't have access to them.

Either stop using anonymous types, or use [InternalsVisibleToAttribute] to make the type visible to other assemblies. Within the assembly containing the type which creates the instance of the anonymous type, use:

[InternalsVisibleTo("ExternalLibrary")]

(I'd actually expect the issue to be on SubItem rather than SubSub...)

Upvotes: 6

Related Questions