我正在尝试做这样的事情:
public static class Validate
{
public static void AgainstNull(string str)
{
if (String.IsNullOrWhiteSpace(str))
{
// how do I know the property name in the calling code?
throw new ArgumentNullException("property name from caller");
}
}
}
这样我就可以在我的代码库中使用与此类似的模式:
public void Foo(string bar)
{
Validate.AgainstNull(bar);
// other processing here
}
我如何知道从我的validate方法中的调用代码传入的属性的名称?
答案 0 :(得分:3)
正如Chris Sinclair所提到的,你可以使用LINQ表达式,这里是这样一个代码的例子:
public static class Validate
{
public static void AgainstNull(System.Linq.Expressions.Expression<Func<string>> expr)
{
var str = expr.Compile().Invoke();
if (str == null)
{
string name = (expr.Body as System.Linq.Expressions.MemberExpression).Member.Name;
throw new ArgumentNullException(name);
}
}
}
答案 1 :(得分:2)
这不是直接可能的,但是有一种技术/黑客允许通过使它们成为匿名类型的成员来检索参数名称。
根据您的示例, 不合适。它引入了不必要的歧义,并且需要弱类型的方法签名。它也比仅传递相关参数的字符串名称慢得多。
同样,不要将其用于所述目的。
<强>代码强>
void Main()
{
Foo( "hello", "world", 123, false );
}
private static void Foo( string bar, string baz, int abc, bool xyz )
{
Evaluate( new { bar, baz, abc, xyz } );
}
private static void Evaluate( object o )
{
var properties = System.ComponentModel.TypeDescriptor.GetProperties( o );
foreach( System.ComponentModel.PropertyDescriptor propertyDescriptor in properties )
{
var value = propertyDescriptor.GetValue( o );
Console.WriteLine( "Name: {0}, Value: {1}", propertyDescriptor.Name, value );
}
}
<强>输出强>
Name: bar, Value: hello
Name: baz, Value: world
Name: abc, Value: 123
Name: xyz, Value: False
这种模式何时适合?
值得注意的是,ASP.Net MVC框架广泛使用匿名类型作为语法快捷方式。 ComponentModel
代码直接来自RouteValueDictionary
。
答案 2 :(得分:1)
简单回答:你做不到。
我认为在较新版本的.NET中有attributes会有所帮助,但看起来他们也不会这样做。
答案 3 :(得分:0)
您可以使用表达式树来获取参数名称
public static class Validate
{
public static void AgainstNull(string str)
{
if (String.IsNullOrWhiteSpace(str))
{
var parametersNames = GetParameterNames(() => AgainstNull(str));
throw new ArgumentNullException(parametersNames[0]);
}
}
private static string[] GetParameterNames(Expression<Action> expression)
{
var methodInfo = ((MethodCallExpression)expression.Body).Method;
var names = methodInfo.GetParameters().Select(p => p.Name);
return names.ToArray();
}
}
[Fact]
public void AgainstNullTest()
{
var ex = Assert.Throws<ArgumentNullException>(() => Validate.AgainstNull(string.Empty));
Assert.True(ex.Message.EndsWith("str"));
}