How to use Expression to build an Anonymous Type?
How to use Expression to build an Anonymous Type?
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(exp);
object myObj = lambda.Compile().DynamicInvoke();
But how do you use Expression to create an Anonymous class?
//anonymousType = typeof(new Name="abc", Num=123);
Type anonymousType = Expression.NewAnonymousType??? <--How to do ?
var exp = Expression.New(anonymousType);
var lambda = LambdaExpression.Lambda(exp);
object myObj = lambda.Compile().DynamicInvoke();
@Flash, this is not possible, at least not directly. The compiler does a lot of "magic" for you when you create anonymous types -- it's syntactic sugar for actually declaring a genuine C# class with a bunch of properties. The compiler just does all this for you. There is no expression tree type that actually does all this for you automatically. If you look at the link I referenced, it provides a workaround. However, it uses Reflection.Emit, which is not for the feint of heart.
– Kirk Woll
Sep 18 '10 at 6:23
Kirk: The OP wants to construct an anonymous class, not create one from scratch. As long as he knows at compile time what the properties' names and types are, he can get the compiler to create the type for him and all he has to do is figure out how to instance it up.
– Gabe
Sep 18 '10 at 6:34
@Gabe, I don't agree with your interpretation of what the OP wanted, but I suppose we'll see. ;)
– Kirk Woll
Sep 18 '10 at 6:36
Kirk: Based on the OP's example of
var exp = Expression.New(typeof(MyClass));
it would appear as though his notion of "create a class" is really "create an instance of an existing class". If he wanted to create a new class, it wouldn't make sense for it to be anonymous.– Gabe
Sep 18 '10 at 6:45
var exp = Expression.New(typeof(MyClass));
3 Answers
3
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
:
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
:
Activator.CreateInstance
Name = ghi, Num = 789
Type anonType = new Name = "abc", Num = 123 .GetType();
object myObj = Activator.CreateInstance(anonType, "ghi", 789);
Console.WriteLine(myObj);
But, Type anonType = new Name = "abc", Num = 123 .GetType(); <--It is static code,not be dynamic code.
– Flash
Sep 18 '10 at 7:54
@Flash: If you are under the impression that the C# code
new Name = "abc", Num = 123
, when used in a LINQ expression, creates a new type at run-time, then you are mistaken. The compiler creates the type at compile-time, and the generated Expression Tree is indistinguishable from one that uses a non-anonymous type.– Timwi
Sep 18 '10 at 8:28
new Name = "abc", Num = 123
Flash: You want dynamic anonymous types? What do you intend to do with them?
– Gabe
Sep 18 '10 at 12:24
I personally prefer to use
Type anonType = new Name = default(string), Num = default(int) .GetType();
when defining the anonymous type as I find it makes it clearer to separate the definition from the use.– Lukazoid
Feb 14 '12 at 12:14
Type anonType = new Name = default(string), Num = default(int) .GetType();
Usually, you would make method containing this code generic, so that one of it's paramters of type T would be anonymous object. You could then use
typeof(T).GetType()
instead of inlining new ...
in method body.– ghord
May 18 '13 at 16:17
typeof(T).GetType()
new ...
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.
Expression.New(Type)
ConstructorInfo
Expression.New
Type
ConstructorInfo
Expression.New
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();
This is a clever solution. But usually the reason one needs to write something using expression trees (the API) is precisely because one doesn't have this info at compile-time. If one did, they would have used ordinary C# expressions in the first place.
– Kirk Woll
Sep 18 '10 at 6:33
@Kirk OPs code beg to differ. ANd there's plenty of situations where you'd know the type but still had to build an ExpressionTree. DynamicLinq-2-Sql for one
– Rune FS
Sep 18 '10 at 8:01
Just nitpicking, anonymous types have empty constructors if the anonymous type is
new
:)– nawfal
Aug 19 '15 at 12:23
new
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:
DynamicInvoke
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.
AnonymousInstantiator
string
int
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Possible dup of: stackoverflow.com/questions/606104/…
– Kirk Woll
Sep 18 '10 at 6:20