programing

INotifyPropertyChanged 속성 이름 - 하드 코드 대 반사?

stoneblock 2023. 4. 19. 21:53

INotifyPropertyChanged 속성 이름 - 하드 코드 대 반사?

INotify를 사용할 때 속성 이름을 지정하는 가장 좋은 방법은 무엇입니까?속성이 변경되었습니까?

대부분의 예에서는 속성 이름을 PropertyChanged 이벤트의 인수로 하드코드합니다.Method Base를 사용할까 생각 중입니다.Get Current Method 입니다.Name. Substring(4)이지만 반사 오버헤드가 약간 불안합니다.

가지 잊지 한입니다.PropertyChanged이벤트는 주로 반사를 사용하여 명명된 속성의 값을 얻는 구성 요소에 의해 소비됩니다.

가장 명백한 예는 데이터 바인딩입니다.

할 때PropertyChangedevent, 속성 이름을 파라미터로 전달하면 이 이벤트의 서브스크라이버가 예를 들어 다음과 같이 호출함으로써 리플렉션을 사용할 가능성이 높다는 을 알 수 있습니다.GetProperty)PropertyInfo 、 。GetValueMethodInfo라고 합니다.메서드를은 Property getter보다 듭니다.이 메서드에는GetProperty이는 메타 데이터만 쿼리합니다.(데이터 바인딩은 TypeDescriptor 전체에 의존하지만 기본 구현에서는 리플렉션을 사용합니다.)

따라서 PropertyChanged 실행 시 하드코드 속성명을 사용하는 것이 리플렉션을 사용하는 것보다 효과적이지만 IMHO는 생각의 균형을 맞추는 것이 중요합니다.경우에 따라서는 퍼포먼스 오버헤드가 그다지 중요하지 않을 수 있으며 강력한 유형의 이벤트 발생 메커니즘에서 이점을 얻을 수 있습니다.

퍼포먼스가 문제가 되지 않을 때 C# 3.0에서 사용하는 것은 다음과 같습니다.

public class Person : INotifyPropertyChanged
{
    private string name;

    public string Name
    {
        get { return this.name; }
        set 
        { 
            this.name = value;
            FirePropertyChanged(p => p.Name);
        }
    }

    private void FirePropertyChanged<TValue>(Expression<Func<Person, TValue>> propertySelector)
    {
        if (PropertyChanged == null)
            return;

        var memberExpression = propertySelector.Body as MemberExpression;
        if (memberExpression == null)
            return;

        PropertyChanged(this, new PropertyChangedEventArgs(memberExpression.Member.Name));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

위해 하고, an an an an an express an an로 사용하는 것에 주의해 .Expression:

FirePropertyChanged(p => p.Name);

.NET 4.5(C# 5.0)에는 CallerMemberName이라는 새로운 속성이 있습니다.이 속성은 개발자가 속성 이름을 변경하기로 결정했을 때 버그가 발생하는 것을 방지하는 데 도움이 됩니다.다음은 예를 제시하겠습니다.

public event PropertyChangedEventHandler PropertyChanged = delegate { };

public void OnPropertyChanged([CallerMemberName]string propertyName="")
{
    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

private string name;
public string Name
{
    get { return name; }
    set 
    { 
        name = value;
        OnPropertyChanged();
    }
}

특히 Inotify 이후로 반사 오버헤드는 상당히 과잉입니다.Property Changed는 호출이 많이 됩니다.가능하면 값을 하드코드하는 것이 가장 좋습니다.

퍼포먼스에 관심이 없다면 아래에 기재되어 있는 다양한 접근방식을 보고 최소한의 코딩이 필요한 것을 선택하겠습니다.명시적 콜의 필요성을 완전히 배제하기 위해 어떤 조치를 취할 수 있다면 그것이 최선입니다(AOP 등).

표현 트리의 사용에 관련된 성능 적중은 표현 트리의 반복적인 해상도에 기인합니다.

다음 코드에서는 여전히 식 트리를 사용하고 있기 때문에 리팩터링과 난독화가 용이하다는 장점이 있지만 실제로는 모든 변경 알림에 대해 PropertyChangedEventArgs 개체를 새로 만드는 일반적인 기술보다 약 40% 더 빠릅니다(매우 거친 테스트).

각 속성에 대해 정적 PropertyChangedEventArgs 개체를 캐시하기 때문에 식 트리의 성능 저하를 방지하고 더 빠릅니다.

아직 하고 있지 않은 것이 있습니다.즉, 제공된 PropertChangedEventArgs 객체의 속성명이 사용되고 있는 속성과 일치하는지 디버깅 빌드를 체크하는 코드를 추가할 예정입니다.현재로서는 개발자가 잘못된 객체를 제공할 수 있습니다.

확인해 주세요.

    public class Observable<T> : INotifyPropertyChanged
    where T : Observable<T>
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected static PropertyChangedEventArgs CreateArgs(
        Expression<Func<T, object>> propertyExpression)
    {
        var lambda = propertyExpression as LambdaExpression;
        MemberExpression memberExpression;
        if (lambda.Body is UnaryExpression)
        {
            var unaryExpression = lambda.Body as UnaryExpression;
            memberExpression = unaryExpression.Operand as MemberExpression;
        }
        else
        {
            memberExpression = lambda.Body as MemberExpression;
        }

        var propertyInfo = memberExpression.Member as PropertyInfo;

        return new PropertyChangedEventArgs(propertyInfo.Name);
    }

    protected void NotifyChange(PropertyChangedEventArgs args)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, args);
        }
    }
}

public class Person : Observable<Person>
{
    // property change event arg objects
    static PropertyChangedEventArgs _firstNameChangeArgs = CreateArgs(x => x.FirstName);
    static PropertyChangedEventArgs _lastNameChangeArgs = CreateArgs(x => x.LastName);

    string _firstName;
    string _lastName;

    public string FirstName
    {
        get { return _firstName; }
        set
        {
            _firstName = value;
            NotifyChange(_firstNameChangeArgs);
        }
    }

    public string LastName
    {
        get { return _lastName; }
        set
        {
            _lastName = value;
            NotifyChange(_lastNameChangeArgs);
        }
    }
}

로마자:

"Person" 파라미터는 필요 없습니다.따라서 다음과 같은 완전 범용 스니펫이면 충분합니다.

private int age;
public int Age
{
  get { return age; }
  set
  {
    age = value;
    OnPropertyChanged(() => Age);
  }
}


private void OnPropertyChanged<T>(Expression<Func<T>> exp)
{
  //the cast will always succeed
  MemberExpression memberExpression = (MemberExpression) exp.Body;
  string propertyName = memberExpression.Member.Name;

  if (PropertyChanged != null)
  {
    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  }
}

...단, 디버깅빌드에서 조건부 검증이 이루어진 문자열 파라미터를 고수하는 것을 선호합니다.Josh Smith는 이에 대한 좋은 샘플을 올렸습니다.

Inotify를 구현하는 기본 클래스속성 변경

건배 :) 필리핀

제안하신 함수의 사용법과 단순성은 알겠습니다만, 반영에 의한 실행 코스트를 고려할 때, 네, 좋지 않은 생각입니다.이 시나리오에서 사용하는 것은, Notify Property 이벤트 기동과 함께 속성의 기입에 시간과 에러를 이용할 수 있도록, 코드 스니펫을 적절히 추가하는 것입니다.

제가 생각할 수 있는 또 다른 아주 좋은 방법은

구현 Property Affects(속성 변경)
AOP: 애트 a a a a a a a a a a a

코드프로젝트에 관한 좋은 기사: AOP의 INotify 구현속성 변경

이 토론에 관심을 가질 수 있습니다.

"베스트 프랙티스:Inotify 구현 방법Property Changed 맞죠?"

너무.

C# 6.0에는 name of() 키워드가 있기 때문에 컴파일 시에 평가되기 때문에 하드코드된 값으로 퍼포먼스가 유지되며 통지된 속성과의 불일치로부터 보호됩니다.

public event PropertyChangedEventHandler PropertyChanged;

protected void NotifyPropertyChanged(string info)
{       
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
}
public string SelectedItem
{
    get
    {
        return _selectedItem;
    }
    set
    {
        if (_selectedItem != value)
        {
            _selectedItem = value;
            NotifyPropertyChanged(nameof(SelectedItem));
        }
    }
}
private string _selectedItem;

하드코드와 리플렉션 중 어느 쪽을 선택해도 문제가 없습니다.notify property weaver입니다.

이 Visual Studio 패키지를 사용하면 권한을 잃지 않고 반사(유지보수성, 가독성 등)의 이점을 누릴 수 있습니다.

실제로는 이노티파이(INotify)를 구현하기만 하면 됩니다.Property Changed는 컴파일 시 모든 "알림 내용"을 추가합니다.

코드를 완전히 최적화하려는 경우에도 이 방법은 완전히 매개 변수화할 수 있습니다.

예를 들어 notifypropertyweaver를 사용하면 에디터에 다음 코드가 표시됩니다.

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public string GivenNames { get; set; }
    public string FamilyName { get; set; }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }
}

대신:

public class Person : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    private string givenNames;
    public string GivenNames
    {
        get { return givenNames; }
        set
        {
            if (value != givenNames)
            {
                givenNames = value;
                OnPropertyChanged("GivenNames");
                OnPropertyChanged("FullName");
            }
        }
    }

    private string familyName;
    public string FamilyName
    {
        get { return familyName; }
        set
        {
            if (value != familyName)
            {
                familyName = value;
                OnPropertyChanged("FamilyName");
                OnPropertyChanged("FullName");
            }
        }
    }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }

    public virtual void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

프랑스어 사용자: Améliores la lisibilité de votre code et simplifiez vous la vie avec notifypropertyweaver

또한 디버깅과 디버깅에서 메서드 이름의 취득이 다르게 기능하는 문제가 발견되었습니다.릴리스 빌드:

http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/244d3f24-4cc4-4925-aebe-85f55b39ec92

(당사가 사용하고 있는 코드는 당신이 제안한 방식으로는 정확하게 반영되지 않았지만, 속성 이름을 하드코딩하는 것이 가장 빠르고 신뢰할 수 있는 솔루션이라고 확신했습니다.)

실험으로 한번 해봤는데, 메모리에서는 정상적으로 동작했고, 모든 속성 이름을 문자열로 하드코드할 필요가 없어졌습니다.데스크톱에서 대용량 서버 애플리케이션을 구축하면 성능 문제가 발생할 수 있습니다.

protected void OnPropertyChanged()
{
    OnPropertyChanged(PropertyName);
}

protected string PropertyName
{
    get
    {
        MethodBase mb = new StackFrame(1).GetMethod();
        string name = mb.Name;
        if(mb.Name.IndexOf("get_") > -1)
            name = mb.Name.Replace("get_", "");

        if(mb.Name.IndexOf("set_") > -1)
            name = mb.Name.Replace("set_", "");

        return name;
    }
}

리플렉션 베이스의 문제는, 가격이 비싸고, 그다지 빠르지 않다는 것입니다.물론 리팩터링에 훨씬 유연하고 덜 취약합니다.

하지만, 특히 자주 전화할 때, 그것은 정말로 성능을 해칠 수 있습니다.스택 프레임 방식도 CAS에 문제가 있다고 생각합니다(예를 들어 XBAP 등의 제한된 신뢰 수준).하드코드로 하는 게 최선이야

WPF에서 빠르고 유연한 속성 알림을 찾는 경우 솔루션이 있습니다. - use Dependency Object : ) depend what was for for for for 。종속성을 사용하지 않거나 스레드 선호도 문제가 우려되는 경우 속성 이름을 상수로 이동하고 Boom!잘 부탁드립니다.

Inotify는 피하는 것이 좋습니다.속성이 모두 변경되었습니다.불필요한 부기 코드를 프로젝트에 추가합니다.Update Controls 사용을 검토합니다.대신 NET을 사용합니다.

또 다른 접근법: http://www.codeproject.com/Articles/450688/Enhanced-MVVM-Design-w-Type-Safe-View-Models-TVM

블로그 투고를 봐주세요.http://khason.net/dev/inotifypropertychanged-auto-wiring-or-how-to-get-rid-of-redundant-code

언급URL : https://stackoverflow.com/questions/141370/inotifypropertychanged-property-name-hardcode-vs-reflection