给出以下类型
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", ...)
让我觉得笨拙。)
答案 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个)构造函数参数。