Code below is working well as long as I have class ClassSameAssembly
in same assembly as class Program
.
But when I move class ClassSameAssemb
Below solution worked for me in my console application projects
Put this [assembly: InternalsVisibleTo("YourAssemblyName")] in \Properties\AssemblyInfo.cs of the separate project with function returning dynamic object.
"YourAssemblyName" is the assembly name of calling project. You can get that through Assembly.GetExecutingAssembly().FullName by executing it in calling project.
A cleaner solution would be:
var d = ClassSameAssembly.GetValues().ToDynamic();
Which is now an ExpandoObject.
Remember to reference:
Microsoft.CSharp.dll
I believe the problem is that the anonymous type is generated as internal
, so the binder doesn't really "know" about it as such.
Try using ExpandoObject instead:
public static dynamic GetValues()
{
dynamic expando = new ExpandoObject();
expando.Name = "Michael";
expando.Age = 20;
return expando;
}
I know that's somewhat ugly, but it's the best I can think of at the moment... I don't think you can even use an object initializer with it, because while it's strongly typed as ExpandoObject
the compiler won't know what to do with "Name" and "Age". You may be able to do this:
dynamic expando = new ExpandoObject()
{
{ "Name", "Michael" },
{ "Age", 20 }
};
return expando;
but that's not much better...
You could potentially write an extension method to convert an anonymous type to an expando with the same contents via reflection. Then you could write:
return new { Name = "Michael", Age = 20 }.ToExpando();
That's pretty horrible though :(
You could use [assembly: InternalsVisibleTo("YourAssemblyName")]
to make you assembly internals visible.
Here is a rudimentary version of an extension method for ToExpandoObject that I'm sure has room for polishing.
public static ExpandoObject ToExpandoObject(this object value)
{
// Throw is a helper in my project, replace with your own check(s)
Throw<ArgumentNullException>.If(value, Predicates.IsNull, "value");
var obj = new ExpandoObject() as IDictionary<string, object>;
foreach (var property in value.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
obj.Add(property.Name, property.GetValue(value, null));
}
return obj as ExpandoObject;
}
[TestCase(1, "str", 10.75, 9.000989, true)]
public void ToExpandoObjectTests(int int1, string str1, decimal dec1, double dbl1, bool bl1)
{
DateTime now = DateTime.Now;
dynamic value = new {Int = int1, String = str1, Decimal = dec1, Double = dbl1, Bool = bl1, Now = now}.ToExpandoObject();
Assert.AreEqual(int1, value.Int);
Assert.AreEqual(str1, value.String);
Assert.AreEqual(dec1, value.Decimal);
Assert.AreEqual(dbl1, value.Double);
Assert.AreEqual(bl1, value.Bool);
Assert.AreEqual(now, value.Now);
}
ToExpando extension method (mentioned in Jon's answer) for the brave ones
public static class ExtensionMethods
{
public static ExpandoObject ToExpando(this object obj)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(obj))
{
var value = propertyDescriptor.GetValue(obj);
expando.Add(propertyDescriptor.Name, value == null || new[]
{
typeof (Enum),
typeof (String),
typeof (Char),
typeof (Guid),
typeof (Boolean),
typeof (Byte),
typeof (Int16),
typeof (Int32),
typeof (Int64),
typeof (Single),
typeof (Double),
typeof (Decimal),
typeof (SByte),
typeof (UInt16),
typeof (UInt32),
typeof (UInt64),
typeof (DateTime),
typeof (DateTimeOffset),
typeof (TimeSpan),
}.Any(oo => oo.IsInstanceOfType(value))
? value
: value.ToExpando());
}
return (ExpandoObject)expando;
}
}