在C#中缺lesstypes安全的数据绑定的'nameof'操作符的解决方法?
在C#中包含一个nameof
符的nameof
已经引起很多人的nameof
。 作为该运算符如何工作的示例, nameof(Customer.Name)
将返回string"Name"
。
我有一个域对象。 我必须将其绑定。 然后我需要属性名称作为string。 我希望他们是types安全的。
我记得在.NET 3.5中遇到了一个解决方法,它提供了nameof
和lambdaexpression式的function。 但是,我一直无法find这个解决方法。 任何人都可以提供解决方法给我?
如果可能的话,我也有兴趣在.NET 2.0中实现nameof
的function。
这段代码基本上这样做:
class Program { static void Main() { var propName = Nameof<SampleClass>.Property(e => e.Name); Console.WriteLine(propName); } } public class Nameof<T> { public static string Property<TProp>(Expression<Func<T, TProp>> expression) { var body = expression.Body as MemberExpression; if(body == null) throw new ArgumentException("'expression' should be a member expression"); return body.Member.Name; } }
(当然这是3.5代码…)
虽然reshefm和Jon Skeet展示了使用expression式来完成这个工作的正确方法,但值得注意的是有一个更便宜的方法来完成方法名称:
用你的方法包装一个委托,得到MethodInfo,你很好。 这是一个例子:
private void FuncPoo() { } ... // Get the name of the function string funcName = new Action(FuncPoo).Method.Name;
不幸的是,这只适用于方法; 它不适用于属性,因为你不能让委托给属性getter或setter方法。 (看起来像一个愚蠢的限制,海事组织。)
解决方法是使用expression式树,并分开expression式树来查找相关的MemberInfo
。 在这个说明中有更多的细节和评论(虽然不是代码来拉出成员 – 我相信这是另一个SO问题)。
不幸的是,由于expression式树在.NET 2.0中不存在,所以实际上没有等价的东西。
避免拼写错误的一个解决scheme是拥有一组访问器,为特定的属性获取相关的PropertyInfo
,并对其进行unit testing。 那将是唯一有string的地方。 这样可以避免重复,使重构变得更容易,但是有点恶劣。
对reshefm做了什么扩展,简化了nameof()运算符的用法,并给出了方法和类成员和方法的名称:
/// <summary> /// Provides the <see cref="nameof"/> extension method that works as a workarounds for a nameof() operator, /// which should be added to C# sometime in the future. /// </summary> public static class NameOfHelper { /// <summary> /// Returns a string represantaion of a property name (or a method name), which is given using a lambda expression. /// </summary> /// <typeparam name="T">The type of the <paramref name="obj"/> parameter.</typeparam> /// <typeparam name="TProp">The type of the property (or the method's return type), which is used in the <paramref name="expression"/> parameter.</typeparam> /// <param name="obj">An object, that has the property (or method), which its name is returned.</param> /// <param name="expression">A Lambda expression of this pattern: x => x.Property <BR/> /// Where the x is the <paramref name="obj"/> and the Property is the property symbol of x.<BR/> /// (For a method, use: x => x.Method()</param> /// <returns>A string that has the name of the given property (or method).</returns> public static string nameof<T, TProp>(this T obj, Expression<Func<T, TProp>> expression) { MemberExpression memberExp = expression.Body as MemberExpression; if (memberExp != null) return memberExp.Member.Name; MethodCallExpression methodExp = expression.Body as MethodCallExpression; if (methodExp != null) return methodExp.Method.Name; throw new ArgumentException("'expression' should be a member expression or a method call expression.", "expression"); } /// <summary> /// Returns a string represantaion of a property name (or a method name), which is given using a lambda expression. /// </summary> /// <typeparam name="TProp">The type of the property (or the method's return type), which is used in the <paramref name="expression"/> parameter.</typeparam> /// <param name="expression">A Lambda expression of this pattern: () => x.Property <BR/> /// Where Property is the property symbol of x.<BR/> /// (For a method, use: () => x.Method()</param> /// <returns>A string that has the name of the given property (or method).</returns> public static string nameof<TProp>(Expression<Func<TProp>> expression) { MemberExpression memberExp = expression.Body as MemberExpression; if (memberExp != null) return memberExp.Member.Name; MethodCallExpression methodExp = expression.Body as MethodCallExpression; if (methodExp != null) return methodExp.Method.Name; throw new ArgumentException("'expression' should be a member expression or a method call expression.", "expression"); } }
要使用它:
static class Program { static void Main() { string strObj = null; Console.WriteLine(strObj.nameof(x => x.Length)); //gets the name of an object's property. Console.WriteLine(strObj.nameof(x => x.GetType())); //gets the name of an object's method. Console.WriteLine(NameOfHelper.nameof(() => string.Empty)); //gets the name of a class' property. Console.WriteLine(NameOfHelper.nameof(() => string.Copy(""))); //gets the name of a class' method. } }
除非有人改变主意, nameof
运营商的nameof
看起来就像C#6中的。下面是关于它的devise会议logging:
接受的解决scheme是好的,简单和优雅。
然而,build立一个expression式树是昂贵的,我需要整个属性path。
所以我改变了一下。 它根本不是优雅的,但是它在大多数情况下很简单,
public static string Property<TProp>(Expression<Func<T, TProp>> expression) { var s = expression.Body.ToString(); var p = s.Remove(0, s.IndexOf('.') + 1); return p; }
例:
? Nameof<DataGridViewCell>.Property(c => c.Style.BackColor.A); "Style.BackColor.A"
这是C#6.0中的语言的一部分
reshefm的答案相当不错,但这是一个简单的API IMO:
用法示例: NameOf.Property(() => new Order().Status)
using System; using System.Diagnostics.Contracts; using System.Linq.Expressions; namespace AgileDesign.Utilities { public static class NameOf { ///<summary> /// Returns name of any method expression with any number of parameters either void or with a return value ///</summary> ///<param name = "expression"> /// Any method expression with any number of parameters either void or with a return value ///</param> ///<returns> /// Name of any method with any number of parameters either void or with a return value ///</returns> [Pure] public static string Method(Expression<Action> expression) { Contract.Requires<ArgumentNullException>(expression != null); return ( (MethodCallExpression)expression.Body ).Method.Name; } ///<summary> /// Returns name of property, field or parameter expression (of anything but method) ///</summary> ///<param name = "expression"> /// Property, field or parameter expression ///</param> ///<returns> /// Name of property, field, parameter ///</returns> [Pure] public static string Member(Expression<Func<object>> expression) { Contract.Requires<ArgumentNullException>(expression != null); if(expression.Body is UnaryExpression) { return ((MemberExpression)((UnaryExpression)expression.Body).Operand).Member.Name; } return ((MemberExpression)expression.Body).Member.Name; } } }
完整的代码在这里: http : //agiledesignutilities.codeplex.com/SourceControl/changeset/view/b76cefa4234a#GeneralPurpose/NameOf.cs