linq 如何使用表达式构建匿名类型?

cunj1qz1  于 9个月前  发布在  其他
关注(0)|答案(4)|浏览(131)

在C# 3.0中,你可以使用表达式来创建一个具有以下语法的类:

var exp = Expression.New(typeof(MyClass));
var lambda = LambdaExpression.Lambda(exp);
object myObj = lambda.Compile().DynamicInvoke();

字符串
但是如何使用Expression来创建一个Anonymous类呢?

//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();

yyhrrdl8

yyhrrdl81#

你已经接近了,但是你必须注意匿名类型没有默认的构造函数。下面的代码打印{ 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);

字符串
如果你不需要创建很多这种类型的示例,Activator.CreateInstance也可以(它对少数示例来说更快,但对很多示例来说更慢)。下面的代码打印{ Name = ghi, Num = 789 }

Type anonType = new { Name = "abc", Num = 123 }.GetType();
object myObj = Activator.CreateInstance(anonType, "ghi", 789);
Console.WriteLine(myObj);

cczfrluj

cczfrluj2#

由于匿名类型没有默认的空构造函数,所以不能使用Expression.New(Type)重载.和ConstructorInfo,然后将参数传递给Expression.New方法。
就像这样:

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();

字符串

6gpjuf90

6gpjuf903#

你可以避免使用DynamicInvoke,它非常慢。你可以使用C#中的类型推断来获得匿名类型的泛型示例化。比如:

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();
}

字符串
现在你可以打电话了,

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.


你可以使用AnonymousInstantiator方法来生成函数来示例化任何匿名类型,并带有任意数量的属性,只是你必须首先传递一个适当的示例。输入参数必须作为对象数组传递。如果你担心装箱性能,那么你必须编写一个自定义示例化器,它只接受stringint作为输入参数,但是这种示例化器的使用将受到更多的限制。

zqdjd7g9

zqdjd7g94#

使用动态类型创建:

using DynamicAnonymousType; // nuget

var dynamicType = DynamicFactory.CreateType(
  ("Name", typeof(string)),
  ("Num", typeof(int)),
);

var initExpr = Expression.MemberInit(
  Expression.New(dynamicType),
  new [] {
    Expression.Bind(dynamicType.GetProperty("Name"), Expression.Constant("example", typeof(string))),
    Expression.Bind(dynamicType.GetProperty("Num"), Expression.Constant(123, typeof(int))),
  }
);

字符串

相关问题