Как передать имя свойств класса методу без использования строки [duplicate]

В основном, в первом примере вы привязываете i внутри обработчика onclick непосредственно к i вне обработчика onclick. Поэтому, когда i вне обработчика onclick изменяется, i внутри обработчика onclick тоже изменяется.

Во втором примере вместо привязки к num в onclick, вы передаете его в функцию, которая затем привязывает его к num в обработчике onclick. Когда вы передаете его в функцию, значение i копируется, не привязывается к num. Поэтому, когда i изменяется, num остается неизменным. Копия происходит потому, что функции в JavaScript являются «замыканиями», что означает, что как только что-то передается в функцию, оно «закрыто» для внешней модификации.

10
задан Davy8 14 July 2009 в 22:16
поделиться

7 ответов

Изменить: nameof прибыл в c # 6. Yay!


Нет nameof / infoof и т. д .; это много обсуждается, но это то, что оно есть.

Существует способ сделать это с использованием лямбда-выражений в .NET 3.5 (и разбора дерева выражений), но на самом деле это не стоит накладные расходы. На данный момент я просто придерживаюсь строк (и модульных тестов, если вы решили не разорвать его).


using System;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reflection;
class Program : INotifyPropertyChanged {
    public event PropertyChangedEventHandler PropertyChanged;
    static void Main() {
        var p = new Program();
        p.PropertyChanged += (s, a) => Console.WriteLine(a.PropertyName);
        p.Name = "abc";
    }
    protected void OnPropertyChanged<T>(Expression<Func<Program, T>> property) {
        MemberExpression me = property.Body as MemberExpression;
        if (me == null || me.Expression != property.Parameters[0]
              || me.Member.MemberType != MemberTypes.Property) {
            throw new InvalidOperationException(
                "Now tell me about the property");
        }
        var handler = PropertyChanged;
        if (handler != null) handler(this,
          new PropertyChangedEventArgs(me.Member.Name));
    }
    string name;
    public string Name {
        get{return name;}
        set {
            name = value;
            OnPropertyChanged(p=>p.Name);
        }
    }
}
8
ответ дан Marc Gravell 23 August 2018 в 01:46
поделиться
  • 1
    Я, вероятно, просто придерживаюсь строк, но для ударов вы можете дать короткий пример кода о том, как разбирать дерево выражений? – Davy8 14 July 2009 в 22:34
  • 2
    Почему вы используете Expression<Func<Program, T>> и p=>p.Name вместо Expression<Func<T>> и ()=>Name? – Svish 15 July 2009 в 14:22
  • 3
    Либо все будет хорошо, но версия, опубликованная, дает понять, что мы ищем свойство на экземпляре, а не просто случайное. – Marc Gravell♦ 15 July 2009 в 14:36
  • 4
    Указание выражения & lt; Func & lt; Program & gt; & gt; & gt; & gt; на вашем базовом классе представлений не позволит подклассам поднять его свойства. Вот почему выражение & lt; Func & lt; T & gt; & gt; & gt; для этой цели лучше. – JoanComasFdz 30 November 2012 в 13:56
  • 5
    Больше неправда! Теперь вы можете использовать nameof. – Casey 6 February 2016 в 05:09

Вы должны проверить это сообщение в блоге . Это дает вам возможность сделать это:

string propertyName = TypeHelper.GetPropertyName<User>(u => u.LastProjectCode);

PropertyInfo property1 = TypeHelper.GetProperty((SomeClass o) => o.InstanceProperty.Length);

PropertyInfo property2 = TypeHelper.GetProperty(() => SomeClass.StaticProperty.Length);

Переименование в Visual Studio / Resharper / Refactor Pro должно работать для вас тогда.

0
ответ дан Brett Veenstra 23 August 2018 в 01:46
поделиться

Свойство PropertyChangedEventArgs принимает только один конструктор, для которого требуется имя свойства как строка. Таким образом, по сути, использование INotifyPropertyChanged не означает, что на каком-то уровне, будь то высокая или низкая в вашей архитектуре, вам придется работать со строкой и ручным переименованием.

-1
ответ дан Charlie 23 August 2018 в 01:46
поделиться

Самое простое решение - посмотреть на трассировку стека и полностью удалить каждую явную ссылку на свойство.

public String Name
{
    get { return this.name; }
    set
    {
        if (value != this.name)
        {
            this.RaisePropertyChanging();
            this.name = value;
            this.RaisePropertyChanged();
        }
    }
}
private String name = null;

private void RaisePropertyChanged()
{
    String propertyName =
       new StackTrace().GetFrame(1).GetMethod().Name.SubString(4);

    PropertyChangedEventHandler handler = this.PropertyChanged;
    if (handler != null)
    {
        handler(new PropertyChangedEventArgs(propertyName));
    }
}

Код выводит имя свойства через трассировку стека из метода календаря - это метод установки свойств с именем set_<PropertyName>. Если компилятор больше не следует этому соглашению об именах, код прерывается.

Другим решением является получение имени свойства из лямбда-выражения.

public static String GetPropertyNameFromLambdaExpression<TObject, TProperty>(
    Expression<Func<TObject, TProperty>> expression)
{
    return ((MemberExpression)expression.Body).Member.Name;
}

Например

GetPropertyNameFromLambdaExpression<String, Int32>(s => s.Length)

вернет «Length», как ожидалось. Производственная версия кода действительно требует дополнительных проверок и лучшей интеграции в остальную часть кода. Например, можно использовать вывод типа для общих аргументов.

UPDATE

И есть третье решение - вы можете использовать MethodBase.GetCurrentMethod() внутри свойства getter или setter для получения имя метода setter или getter.

public String Name
{
    get { return this.name; }
    set
    {
        if (value != this.name)
        {
            String propertyName = MethodBase.GetCurentMethod().Name.SubString(4);

            this.RaisePropertyChanging(propertyName);
            this.name = value;
            this.RaisePropertyChanged(propertyName);
        }
    }
}
private String name = null;
2
ответ дан Daniel Brückner 23 August 2018 в 01:46
поделиться
  • 1
    Это решение более хрупкое, чем просто определение имени свойства в виде строки. – Charlie 14 July 2009 в 22:52
  • 2
    Это выглядит интересно. Однако, не проверяя документацию, я не могу понять, для чего нужен вызов SubString. Возвращает ли GetMethod () название странное? – Tom Juergens 14 July 2009 в 22:54
  • 3
    Свойство реализуется двумя способами. public MyType MyProperty {get; задавать; } реализуется как public void set_MyProperty (значение MyType) {} и public MyType get_MyProperty (). Следовательно, вы должны удалить set_ и get_ из имени возвращаемого метода, чтобы получить имя свойства. – Daniel Brückner 14 July 2009 в 22:59
  • 4
    Да правильно. Очевидно. Уже поздно ;-) – Tom Juergens 14 July 2009 в 23:01
  • 5
    Почему SubString (4)? – Svish 15 July 2009 в 14:23

У C # 5, похоже, есть решение. С атрибутом CallerMemberName , который может использоваться с параметрами ( Один пример в сети ).

class Employee : INotifyPropertyChanged
{
    private string _Name;
    public string Name
    {
        get { return _Name; }

        set
        {
            _Name = value;
            RaisePropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged([CallerMemberName] string caller = "")
    {
        var temp = PropertyChanged;

        if ( temp != null )
        {
            temp( this, new PropertyChangedEventArgs( caller ) );
        }
    }
}
6
ответ дан Oliver 23 August 2018 в 01:46
поделиться

Теоретически вы можете использовать MethodBase.GetCurrentMethod (). Name.Substring (4) из набора свойств. К сожалению, поиск в Google показывает, что , похоже, имеет значительное влияние на производительность . Еще две вещи, которые следует учитывать:

  • JIT-inlining может повлиять на это неожиданным образом. (stackoverflow.com/questions/616779/can-i-check-if-the-c-compiler-inlined-a-method-call)
  • Теоретически, вызов IL в MethodBase.GetCurrentMethod () может быть тривиально заменена JIT во время выполнения с инструкцией ldtoken, а затем вызовом метода MethodBase.GetMethodFromHandle (), который будет очень быстрым. Я думаю, пользователи просто не выразили необходимости в этом. (msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.ldtoken.aspx)
  • Полностью мое мнение здесь, но я думаю, было бы неплохо иметь fieldof () и methodof () в C #. Я считаю, что это значительно улучшит надежность инструментов анализа кода / рефакторинга в проектах, требующих этой способности.
1
ответ дан Sam Harwell 23 August 2018 в 01:46
поделиться

Не ответ на ваш вопрос, но если вы щелкните правой кнопкой мыши-> Refactor-> Rename a property, он также может переименовать соответствующие строки, включая любые строки, соответствующие имени вашего свойства.

Да, это может быть немного опасно.

0
ответ дан Yoopergeek 23 August 2018 в 01:46
поделиться
  • 1
    Даже переименование комментариев является опасным. Я испортил кучу документации XML в довольно большом проекте, предположив, что эта функция ограничит область комментариями / в переименованном элементе кода. – snarf 14 July 2009 в 22:29
Другие вопросы по тегам:

Похожие вопросы: