有没有办法写一个表达构造函数参数的表达式?

时间:2016-07-07 11:54:17

标签: c#

给出以下类型

class Foo 
{
    public string Bar { get; private set; }

    public Foo(string bar) 
    {
        Bar = bar;
    }
}

我可以写

Expression<Func<Foo, string>> member = foo => foo.Bar;

并获取指向成员Bar的表达式。

是否有类似的方式我可以用某种方式编写一个指向构造函数参数bar的表达式?

我的目标是能够以适应变化的方式指示构造函数参数;例如,在重构构造函数时,我可能会重命名参数 - 这应该继承到表达式。如果我删除它,表达式应该导致构建错误等

更新 - 进一步澄清我想要启用的用法:

考虑一个这样调用的扩展方法(并不重要):

new object().DoSomething<Foo>(foo => foo.Bar);

如果定义如下:

public static void DoSomething<T>(this object o, Expression<Func<T, object>> expr)
{
    // ...
}

我可以访问属性Bar并在扩展方法的主体内部执行各种操作。例如,我可以根据其他地方的输入设置其值。一个具体的用例是AutoMapper,它做了类似这样的事情:

CreateMap<FooDto, Foo>()
    .ForMember(dest => dest.Bar, cfg => cfg.MapFrom(src => src.BarSrc));

表达式dest => dest.Bar表示我们要在其上应用特殊配置的属性(在Foo上),src => src.BarSrc表示我们想要的属性(在FooDto上)从中获取价值。实际上,当需要将FooDto映射到Foo时,AutoMapper可以从源实例中提取BarSrc的值,并将目标实例上的Bar设置为值,使用两个表达式。

我想要做的是,同样地说

CreateMap<FooDto, Foo>()
    .ForCtorParam(dest => /* what do I put here to indicate the bar ctor param? */,
        cfg => cfg.MapFrom(src => src.BarSrc));

(目前的API为.ForCtorParam("bar", ...)让我觉得笨拙。)

2 个答案:

答案 0 :(得分:3)

我不完全确定您的确切用例,但似乎您某处依赖于代码中的参数名称(在重构时未检测到)。

如果您想避免使用参数的硬编码名称,可以在C#6.0中使用nameof

public Foo(string bar)
{
    var nameOfBarParameter = nameof(bar);
    Bar = bar;
}

请注意,这仅适用于参数的声明范围,即本例中构造函数的主体。

如果你需要访问构造函数之外的参数名称,我认为没有办法使用表达式。当然,您可以始终使用反射来检索相关的ParameterInfo和参数名称(但随后您将依赖于参数位置不变):

var ci = typeof(Foo).GetConstructor(new[] { typeof(string) });
var parameterName = ci.GetParameters()[0].Name;

答案 1 :(得分:0)

不确定这是否符合您的需要,但如果您构建表达式树:

Expression<Func<Foo>> expr = () => new Foo("dummy");

使用bar,然后:

ParameterInfo barParameter = ((NewExpression)(expr.Body)).Constructor.GetParameters()[0];

表示(第0个)构造函数参数。