In C# 3.0 you can use Expression to create a class with the following syntax:
var exp = Expression.New(typeof(MyClass));
var lambda = LambdaExpression.Lambda
You're close, but you have to be aware that anonymous types don't have default constructors. The following code prints { Name = def, Num = 456 }
:
Type anonType = new { Name = "abc", Num = 123 }.GetType();
var exp = Expression.New(
anonType.GetConstructor(new[] { typeof(string), typeof(int) }),
Expression.Constant("def"),
Expression.Constant(456));
var lambda = LambdaExpression.Lambda(exp);
object myObj = lambda.Compile().DynamicInvoke();
Console.WriteLine(myObj);
If you don't have to create many instances of this type, Activator.CreateInstance
will do just as well (it's faster for a few instances, but slower for many). This code prints { Name = ghi, Num = 789 }
:
Type anonType = new { Name = "abc", Num = 123 }.GetType();
object myObj = Activator.CreateInstance(anonType, "ghi", 789);
Console.WriteLine(myObj);
You can avoid using DynamicInvoke
which is painfully slow. You could make use of type inference in C# to get your anonymous type instantiated generically. Something like:
public static Func<object[], T> AnonymousInstantiator<T>(T example)
{
var ctor = typeof(T).GetConstructors().First();
var paramExpr = Expression.Parameter(typeof(object[]));
return Expression.Lambda<Func<object[], T>>
(
Expression.New
(
ctor,
ctor.GetParameters().Select
(
(x, i) => Expression.Convert
(
Expression.ArrayIndex(paramExpr, Expression.Constant(i)),
x.ParameterType
)
)
), paramExpr).Compile();
}
Now you can call,
var instantiator = AnonymousInstantiator(new { Name = default(string), Num = default(int) });
var a1 = instantiator(new object[] { "abc", 123 }); // strongly typed
var a2 = instantiator(new object[] { "xyz", 789 }); // strongly typed
// etc.
You could use the AnonymousInstantiator
method to generate functions to instantiate any anonymous type with any number of properties, just that you have to pass an appropriate example first. The input parameters have to be passed as an object array. If you worry boxing performance there then you have to write a custom instantiator which accepts just string
and int
as input parameters, but the use of such an instantiator will be a bit more limited.
Since an anonymous type doesn't have a default empty constructor, you cannot use the Expression.New(Type)
overload ... you have to provide the ConstructorInfo
and parameters to the Expression.New
method. To do that, you have to be able to get the Type ... so you need to make a "stub" instance of the anonymous type, and use that to get the Type
, and the ConstructorInfo
, and then pass the parameters to the Expression.New
method.
Like this:
var exp = Expression.New(new { Name = "", Num = 0 }.GetType().GetConstructors()[0],
Expression.Constant("abc", typeof(string)),
Expression.Constant(123, typeof(int)));
var lambda = LambdaExpression.Lambda(exp);
object myObj = lambda.Compile().DynamicInvoke();