我正在编写一个扩展方法,我碰巧需要在扩展方法中需要扩展方法的字段名称。我无法弄清楚如何做到这一点。
public static Validate Demand<T>(this T parameter)
{
string name = ...
var field = GetField(parameter);
return Validation.CreateValidation(parameter, field, name);
}
void SomeMethod(T someParameter)
{
someParameter.Demand();
}
我希望name
能够someParameter
。
答案 0 :(得分:1)
你做不到。在少数情况下会很好,特别是对于参数检查,但这是不可能的。作为一个方便的例子,我有这个方法:
internal static void ThrowIfNull<T>(this T argument, string name)
where T : class
{
if (argument == null)
{
throw new ArgumentNullException(name);
}
}
我必须致电:
foo.ThrowIfNull("foo");
总比没有好,但是不必提供“foo”位就好了。不幸的是,没有办法做到这一点。你可能会编写一个构建后的IL重写器,它确定了如何调用该方法并从中重建它,但我认为这比利益更多,我怀疑:)
答案 1 :(得分:0)
这是获得我认为你要求的一种方式:
static class Argument
{
public static void NotNull(Expression<Func<Func<object>>> arg)
{
if (arg.Compile()()() == null)
{
var body1 = (Expression<Func<object>>)arg.Body;
var body2 = (MemberExpression)body1.Body;
throw new ArgumentNullException(body2.Member.Name);
}
}
}
像这样使用:
void F(string foo)
{
Argument.NotNull(() => () => foo);
关于这一点的好处是在IDE中重命名foo
将获得所有引用。 (如果字符串中有foo
,则会遗漏。)
如果在紧密循环中使用它,可能会导致性能问题,因为它每次都会调用.Compile()()
。您可以通过添加此重载来优化性能:
public static void NotNull(object value, Expression<Func<Func<object>>> arg)
{
if (value == null)
{
var body1 = (Expression<Func<object>>)arg.Body;
var body2 = (MemberExpression)body1.Body;
throw new ArgumentNullException(body2.Member.Name);
}
}
使用方法如下:
Argument.NotNull(foo, () => () => foo);
它仍然可以重命名,并且每次迭代都会保存该调用。
我建议您在编写代码时使用第一个版本,然后在分析器下运行,并在重要情况下切换到第二个版本。