Обход проблемы из-за отсутствия оператора ‘nameof’ в C # для безопасного хранения данных по типу?

Было много настроений, чтобы включить nameof оператора в C #. В качестве примера того, как будет работать этот оператор, nameof(Customer.Name) вернет строку "Name" .

У меня есть объект домена. И я должен связать это. И тогда мне нужны имена свойств. И я хочу, чтобы они были безопасными по типу.

Я помню, что натолкнулся на обходной путь в .NET 3.5, который предоставил функциональные возможности nameof и участвовал в lambda-выражениях. Однако я не смог найти это решение. Может ли кто-нибудь предоставить это обходное решение для меня?

Я также заинтересован в способе реализации функций nameof в .NET 2.0, если это возможно.

Этот код в основном делает это:

 class Program { static void Main() { var propName = Nameof.Property(e => e.Name); Console.WriteLine(propName); } } public class Nameof { public static string Property(Expression> 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 показывают правильный способ сделать это с помощью выражений, стоит отметить, что для имен методов существует более дешевый способ:

Оберните делегата вокруг вашего метода, получите MethodInfo, и вам хорошо идти. Вот пример:

 private void FuncPoo() { } ... // Get the name of the function string funcName = new Action(FuncPoo).Method.Name; 

К сожалению, это работает только для методов; он не работает для свойств, так как вы не можете делегировать функции getter или setter. (Похоже, это глупое ограничение, ИМО.)

Обходным путем является использование дерева выражений и разделение этого дерева выражений на части, чтобы найти соответствующий MemberInfo . В этой заметке есть немного больше деталей и комментариев (хотя не код, чтобы вытащить участника – это, как я полагаю, в другом вопросе SO).

К сожалению, поскольку деревья выражений не существуют в .NET 2.0, на самом деле нет эквивалента.

Одним из решений, чтобы избежать опечаток, является наличие набора аксессуаров, которые извлекают соответствующий PropertyInfo для определенного свойства, и блок тестирует их. Это было бы единственное место, в котором была строка. Это позволит избежать дублирования и упростить рефакторинг, но это немного драконов.

Расширение того, что было сделано, что упростило использование оператора nameof (), а также дает имена методов и classов и методов:

 ///  /// Provides the  extension method that works as a workarounds for a nameof() operator, /// which should be added to C# sometime in the future. ///  public static class NameOfHelper { ///  /// Returns a string represantaion of a property name (or a method name), which is given using a lambda expression. ///  /// The type of the  parameter. /// The type of the property (or the method's return type), which is used in the  parameter. /// An object, that has the property (or method), which its name is returned. /// A Lambda expression of this pattern: x => x.Property 
/// Where the x is the and the Property is the property symbol of x.
/// (For a method, use: x => x.Method() /// A string that has the name of the given property (or method). public static string nameof(this T obj, Expression> 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"); } /// /// Returns a string represantaion of a property name (or a method name), which is given using a lambda expression. /// /// The type of the property (or the method's return type), which is used in the parameter. /// A Lambda expression of this pattern: () => x.Property
/// Where Property is the property symbol of x.
/// (For a method, use: () => x.Method() /// A string that has the name of the given property (or method). public static string nameof(Expression> 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 оператора выглядит так, как будто оно выходит на C # 6. Вот записки о дизайне:

https://roslyn.codeplex.com/discussions/552376

https://roslyn.codeplex.com/discussions/552377

Принятое решение красиво, просто и элегантно.

Однако построение дерева выражений является дорогостоящим, и мне нужен весь путь свойства.

Поэтому я немного изменил его. Он совсем не изящный, но он прост и хорошо работает в большинстве случаев:

 public static string Property(Expression> expression) { var s = expression.Body.ToString(); var p = s.Remove(0, s.IndexOf('.') + 1); return p; } 

Пример:

 ? Nameof.Property(c => c.Style.BackColor.A); "Style.BackColor.A" 

Это часть языка в C # 6.0

https://msdn.microsoft.com/en-us/magazine/dn802602.aspx

Ответ от 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 { /// /// Returns name of any method expression with any number of parameters either void or with a return value /// /// /// Any method expression with any number of parameters either void or with a return value /// /// /// Name of any method with any number of parameters either void or with a return value /// [Pure] public static string Method(Expression expression) { Contract.Requires(expression != null); return ( (MethodCallExpression)expression.Body ).Method.Name; } /// /// Returns name of property, field or parameter expression (of anything but method) /// /// /// Property, field or parameter expression /// /// /// Name of property, field, parameter /// [Pure] public static string Member(Expression> expression) { Contract.Requires(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

  • Какие подходы доступны для фиктивных данных времени разработки в WPF?
  • WPF привязка данных к интерфейсу, а не к фактическому объекту - возможность литья?
  • Привязать к методу в WPF?
  • Каковы различные режимы привязки WPF?
  • Общий class наблюдаемого словаря для DataBinding / WPF C #
  • Связывание в WPF с элементом массива, заданным свойством
  • Что означает «{Binding Path =.}» В привязке WPF?
  • WPF привязка к локальной переменной
  • Для чего нужен DataContext?
  • Как обнаружить сломанные привязки данных WPF?
  • Привязка OneWayToSource от свойства readonly в XAML
  • Давайте будем гением компьютера.