在运行时解析参数名称

可能重复:
查找传递给C#中函数的变量名称

在C#中,有没有办法(更好的方法)在运行时解析参数的名称?

例如,在以下方法中,如果重命名方法参数,则还必须记住更新传递给ArgumentNullException的字符串文字。

public void Woof(object resource) { if (resource == null) { throw new ArgumentNullException("resource"); } // .. } 

单程:

 static void Main(string[] args) { Console.WriteLine("Name is '{0}'", GetName(new {args})); Console.ReadLine(); } 

此代码还需要一个支持function:

 static string GetName(T item) where T : class { var properties = typeof(T).GetProperties(); Enforce.That(properties.Length == 1); return properties[0].Name; } 

基本上,代码的工作原理是定义一个新的匿名类型,其中包含一个属性,该属性由您想要的参数名称组成。 GetName()然后使用reflection来提取该属性的名称。

这里有更多细节: http : //abdullin.com/journal/2008/12/13/how-to-find-out-variable-or-parameter-name-in-c.html

简答:不,没有。 (那简洁吗?;)

(编辑:贾斯汀的回答可能很重要。它在我的口中留下了不好的味道,但它实现了“不需要将参数名称放入字符串”的目标。我不认为我真的算AOP,因为这真的改变为一种完全不同的方法,而不是回答从方法中获取参数名称的原始问题。)

更长的答案:有一种方法可以找出方法的所有参数 ,但我不认为它在这种情况下有用。

这是一个显示来自几个方法的参数名称的示例:

 using System; using System.Reflection; class Test { static void Main() { Foo(null); Bar(null); } static void Foo(object resource) { PrintParameters(MethodBase.GetCurrentMethod()); } static void Bar(object other) { PrintParameters(MethodBase.GetCurrentMethod()); } static void PrintParameters(MethodBase method) { Console.WriteLine("{0}:", method.Name); foreach (ParameterInfo parameter in method.GetParameters()) { Console.WriteLine(" {0} {1}", parameter.ParameterType, parameter.Name); } } } 

这就是这样,但是如果你有多个参数而你想抛出一个适当的exception,你怎么知道(以安全的方式)使用哪个? 理想情况下,您需要以下内容:

 public void Woof(object resource) { if (resource == null) { throw new ArgumentNullException(infoof(resource)); } // .. } 

神秘的infoof运算符将返回ParameterInfo 。 不幸的是,这不存在。

我处理了同样的问题。 获取参数名称有两种方法,但性能最高的是深入了解IL。 你可以在我的博客文章中看到我在这个问题上的实现示例。 从参数validation中解脱出来 。

这种方法的一个警告是你需要将参数名称作为委托传递,但是为更清洁的代码付出的代价很小:

 public void SomeMethod(string value) { Validate.Argument(() => value).IsNotNull().IsNotEmpty(); } 

这比以下更清洁,更清晰:

 public void SomeMethod(string value) { if (value == null) { throw new ArgumentNullException("value"); } if (value == string.Empty) { throw new ArgumentException("Value cannot be an empty string.", "value"); } } 

静态方法方法允许我在一个流畅的界面中将许多方法链接在一起。 最初返回一个Argument对象,它只允许一个基本的null测试,它返回一个ReferenceArgument对象,然后该对象可以进行额外的validation。 如果被测对象是值类型,则可以使用不同的测试。

API允许进行许多常见测试,但很难捕获所有可能的测试,因此为了提供灵活性,通用测试方法允许提供表达式或函数,而在前者的情况下,表达式实际上可以用作错误消息。

我的示例仅涵盖了一些基础知识,但您可以轻松扩展接口以检查范围并抛出ArgumentOutOfRangeExceptions或从特定基类inheritance的测试对象或实现接口。 有一些类似的实现,但我还没有看到任何获取参数名称。

您可以使用AOP获取此信息。 您可以定义在方法执行之前调用的拦截,并在那里抛出exception。 这也解决了空检查是一个贯穿各领域的问题。

PostSharp是AOP的一个很好的简单实现。

这是你的代码看起来像什么(没有经过测试,但它应该让你非常接近)

 [AttributeUsage(AttributeTargets.Parameter)] public class CanBeNullAttribute : Attribute { private readonly bool canBeNull; public CanBeNullAttribute() : this(true) { } public CanBeNullAttribute(bool canBeNull) { this.canBeNull = canBeNull; } public bool AllowNull { get { return canBeNull; } } } [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class EnforceNullConstraintAttribute : OnMethodInvocationAspect { public override void OnInvocation(MethodInvocationEventArgs eventArgs) { object[] arguments = eventArgs.GetArgumentArray(); ParameterInfo[] parameters = eventArgs.Delegate.Method.GetParameters(); for (int i = 0; i < arguments.Length; i++) { if (arguments[i] != null) continue; foreach (CanBeNullAttribute attribute in parameters[i].GetCustomAttributes(typeof(CanBeNullAttribute), true)) { if (!attribute.AllowNull) throw new ArgumentNullException(parameters[i].Name); } } base.OnInvocation(eventArgs); } } 

现在,您可以修改您的方法:

 [EnforceNullConstraint] public void Woof([CanBeNull(false)] object resource) { // no need to check for null, PostSharp will weave it at compile time // execute logic assured that "resource" is not null } 

你可能想要:

1)

 public static void ThrowIfNull(Expression> expr) { if (expr == null || expr.Compile()() != null) //the compile part is slow return; throw new ArgumentNullException(((MemberExpression)expr.Body).Member.Name); } 

要么

2)

 public static void ThrowIfNull(Expression> expr) { if (expr == null) return; var param = (MemberExpression)expr.Body; if (((FieldInfo)param.Member).GetValue(((ConstantExpression)param.Expression).Value) == null) throw new ArgumentNullException(param.Member.Name); } 

并称之为:

 Class.ThrowIfNull(() => resource); 

但那不是你想要的。 它也慢很多1)比2)慢1000倍。 也许:

3)

 public static void ThrowIfNull(this T item) where T : class { if (item == null) return; var param = typeof(T).GetProperties()[0]; if (param.GetValue(item, null) == null) throw new ArgumentNullException(param.Name); } 

并称之为:

 new { resource }.ThrowIfNull(); 

清洁,比2以上快得多! 🙂

您还可以为对象的属性扩展这些方法。 例如,

 new { myClass.MyProperty1 }.ThrowIfNull(); 

您可以缓存属性值以进一步提高性能,因为属性名称在运行时不会更改。 请参阅相关问题查找传递给函数的变量名称