Reputation: 26408
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
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
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
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