You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#如何使用ExpressionParameter提供的ConstructorInfo调用Expression.New实例化类

我想在C#的Expression.Block内部通过LINQ的Expression.New实例化一个带有公共非无参构造函数的非泛型类ClassToBeInstantiated。

下方是基于@sweeper的答复更新的内容

问题描述

根据官方文档,支持传入构造参数的Expression.New重载均要求传入ConstructorInfo参数,但我无法提前获取该信息,只能在Expression.Block内部动态获取。我可以通过Expression.Call在传入块的ClassToBeInstantiated类型上获取对应的构造函数信息。

但所有需要传入构造参数的Expression.New重载都仅接受ConstructorInfo作为构造函数标识参数,仅调用无参构造函数时才支持直接传入Type参数。我也无法直接将存储了ConstructorInfo的ParameterExpression作为参数传入Expression.New。

核心疑问

请问有没有办法可以绕过这个限制直接使用Expression.New实现需求?我知道可以通过Expression.Call调用ConstructorInfo.Invoke完成实例化,但在我看来Expression.New API本来就应该支持该场景,请问我是不是遗漏了什么用法?

待实例化类示例

public class ClassToBeInstantiated
{
  public ClassToBeInstantiated(int count) { }
}

获取ConstructorInfo的帮助类

public static class GetConstructor
{
  public static ConstructorInfo GetNonGenericConstructorInfo(Type type, params Type[] typeArguments) =>
    type.GetConstructor(typeArguments);
}

报错的测试代码示例

[Test]
public void InstantiateTypeViaExpressionNew()
{
  var typeExpression = Expression.Parameter(typeof(Type), "type");
  var countExpression = Expression.Parameter(typeof(int), "count");
  var ctorExpression = Expression.Variable(typeof(ConstructorInfo), "constructorInfo");
  var block = Expression.Block
  (
    new[] { ctorExpression },
    Expression.Assign(ctorExpression, Expression.Call(typeof(GetConstructor), nameof(GetConstructor.GetNonGenericConstructorInfo),
      Type.EmptyTypes, typeExpression, Expression.Constant(new[] { countExpression.Type }))),
    Expression.New(/* 此处报错,无法直接传入ctorExpression作为参数 */, countExpression)
  );

  var lambda = Expression.Lambda<Func<Type, int, object>>(block, typeExpression, countExpression);
  var func = lambda.Compile();
  var o = func.Invoke(typeof(ClassToBeInstantiated), 4);
  var instance = o as ClassToBeInstantiated;
  Assert.NotNull(instance);
}

使用Expression.Call替代Expression.New的更新方案

基于@Sweeper的答复,我更新了代码示例,供有需要的开发者参考:

更新后的帮助类

我新增了constructorInfoInvokeMethodInfo字段,用于获取ConstructorInfo.Invoke()方法的MethodInfo,供Expression.Block内部调用:

public static class GetConstructor
{
  public static ConstructorInfo GetNonGenericConstructorInfo(Type type, params Type[] typeArguments) =>
    type.GetConstructor(typeArguments);

  public static readonly MethodInfo constructorInfoInvokeMethodInfo = 
    typeof(ConstructorInfo).GetMethod(nameof(ConstructorInfo.Invoke), new[] { typeof(object[]) });
}

更新后的Expression.Block测试代码

我将无法运行的Expression.New替换为Expression.Call,通过ConstructorInfo.Invoke()完成类型实例化:

[Test]
public void InstantiateTypeViaExpressionCall()
{
  var typeExpression = Expression.Parameter(typeof(Type), "type");
  var countExpression = Expression.Parameter(typeof(int), "count");
  var ctorExpression = Expression.Variable(typeof(ConstructorInfo), "constructorInfo");
var block = Expression.Block
(
  new[] { ctorExpression },
  Expression.Assign
  (
    ctorExpression,
    Expression.Call(typeof(Activator), nameof(GetNonGenericConstructorInfo), Type.EmptyTypes, typeExpression, Expression.Constant(new[] { countExpression.Type }))
  ),
  Expression.Call(ctorExpression, constructorInfoInvokeMethodInfo, Expression.NewArrayInit(typeof(object), Expression.Convert(countExpression, typeof(object))))
);

  var lambda = Expression.Lambda<Func<Type, int, object>>(block, typeExpression, countExpression);
  var func = lambda.Compile();
  var o = func.Invoke(typeof(ClassToBeInstantiated), 4);
  var instance = o as ClassToBeInstantiated;
  Assert.NotNull(instance);
}

内容的提问来源于stack exchange,提问作者Ronald Rink 'd-fens'

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 18:24:06