Microsoft는 INotifyPropertyChanged자동 속성에서와 같이 딱딱한 것을 구현 해야합니다.{get; set; notify;}
한다고 생각합니다. 아니면 합병증이 있습니까?
우리는 우리 자신의 속성에 ‘알림’과 같은 것을 구현할 수 있습니까? INotifyPropertyChanged수업 에 구현할 수있는 우아한 솔루션이 있습니까? 아니면 그것을 수행하는 유일한 방법은PropertyChanged 각 속성 이벤트를 입니다.
그렇지 않다면 PropertyChanged  이벤트 를 발생시키기 위해 코드를 자동 생성하는 무언가를 작성할 수 있습니까?
답변
postsharp와 같은 것을 사용하지 않고 사용하는 최소 버전은 다음과 같은 것을 사용합니다.
public class Data : INotifyPropertyChanged
{
    // boiler-plate
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
    protected bool SetField<T>(ref T field, T value, string propertyName)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
    // props
    private string name;
    public string Name
    {
        get { return name; }
        set { SetField(ref name, value, "Name"); }
    }
}각 속성은 다음과 같습니다.
    private string name;
    public string Name
    {
        get { return name; }
        set { SetField(ref name, value, "Name"); }
    }크지 않은; 원하는 경우 기본 클래스로 사용할 수도 있습니다. 에서 bool반환 SetField하면 다른 논리를 적용하려는 경우 비 작동인지 알려줍니다.
또는 C # 5를 사용하면 더 쉽습니다.
protected bool SetField<T>(ref T field, T value,
    [CallerMemberName] string propertyName = null)
{...}다음과 같이 호출 할 수 있습니다 :
set { SetField(ref name, value); }컴파일러가 "Name"자동으로 추가합니다 .
C # 6.0을 사용하면 구현이 더 쉬워집니다.
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}… 그리고 이제 C # 7로 :
protected void OnPropertyChanged(string propertyName)
   => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
protected bool SetField<T>(ref T field, T value,[CallerMemberName] string propertyName =  null)
{
    if (EqualityComparer<T>.Default.Equals(field, value)) return false;
    field = value;
    OnPropertyChanged(propertyName);
    return true;
}
private string name;
public string Name
{
    get => name;
    set => SetField(ref name, value);
}답변
.Net 4.5부터는이를 수행하는 쉬운 방법이 있습니다.
.Net 4.5에는 새로운 발신자 정보 속성이 도입되었습니다.
private void OnPropertyChanged<T>([CallerMemberName]string caller = null) {
     // make sure only to call this if the value actually changes
     var handler = PropertyChanged;
     if (handler != null) {
        handler(this, new PropertyChangedEventArgs(caller));
     }
}함수에 비교자를 추가하는 것이 좋습니다.
EqualityComparer<T>.Default.Equals답변
Marc의 솔루션은 정말 마음에 들지만 리팩토링을 지원하지 않는 “매직 문자열”을 사용하지 않도록 약간 개선 할 수 있다고 생각합니다. 속성 이름을 문자열로 사용하는 대신 람다 식으로 만들 수 있습니다.
private string name;
public string Name
{
    get { return name; }
    set { SetField(ref name, value, () => Name); }
}Marc의 코드에 다음 방법을 추가하면 트릭을 수행합니다.
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
{
    if (selectorExpression == null)
        throw new ArgumentNullException("selectorExpression");
    MemberExpression body = selectorExpression.Body as MemberExpression;
    if (body == null)
        throw new ArgumentException("The body must be a member expression");
    OnPropertyChanged(body.Member.Name);
}
protected bool SetField<T>(ref T field, T value, Expression<Func<T>> selectorExpression)
{
    if (EqualityComparer<T>.Default.Equals(field, value)) return false;
    field = value;
    OnPropertyChanged(selectorExpression);
    return true;
}BTW, 이것은 블로그 게시물  업데이트 URL 에서 영감을
답변
PropertyChanged 추가 기능 이있는 Fody 도 있습니다.
[ImplementPropertyChanged]
public class Person
{
    public string GivenNames { get; set; }
    public string FamilyName { get; set; }
}… 컴파일시 속성 변경 알림을 삽입합니다.
답변
사람들은 성능에 조금 더주의를 기울여야한다고 생각합니다. 바인딩 할 개체가 많거나 (행이 10,000 개 이상인 그리드를 생각할 때) 개체의 값이 자주 변경되는 경우 (실시간 모니터링 앱) 실제로 UI에 영향을줍니다.
나는 여기와 다른 곳에서 발견 된 다양한 구현을 취하고 비교를했다. INotifyPropertyChanged 구현의 성능 비교를 확인하십시오 .
결과를 엿볼 수 있습니다.

답변
내 블로그 ( http://timoch.com/blog/2013/08/annoyed-with-inotifypropertychange/) 에서 Bindable 클래스를 소개합니다. Bindable
은 사전을 속성 백으로 사용합니다. ref 매개 변수를 사용하여 자체 하위 필드를 관리하기 위해 서브 클래스에 필요한 오버로드를 추가하기가 쉽습니다.
- 마술 줄 없음
- 반사 없음
- 기본 사전 조회를 억제하도록 개선 할 수 있습니다
코드:
public class Bindable : INotifyPropertyChanged {
    private Dictionary<string, object> _properties = new Dictionary<string, object>();
    /// <summary>
    /// Gets the value of a property
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="name"></param>
    /// <returns></returns>
    protected T Get<T>([CallerMemberName] string name = null) {
        Debug.Assert(name != null, "name != null");
        object value = null;
        if (_properties.TryGetValue(name, out value))
            return value == null ? default(T) : (T)value;
        return default(T);
    }
    /// <summary>
    /// Sets the value of a property
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value"></param>
    /// <param name="name"></param>
    /// <remarks>Use this overload when implicitly naming the property</remarks>
    protected void Set<T>(T value, [CallerMemberName] string name = null) {
        Debug.Assert(name != null, "name != null");
        if (Equals(value, Get<T>(name)))
            return;
        _properties[name] = value;
        OnPropertyChanged(name);
    }
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}다음과 같이 사용할 수 있습니다 :
public class Contact : Bindable {
    public string FirstName {
        get { return Get<string>(); }
        set { Set(value); }
    }
}답변
실제로이 작업을 직접 시도 할 기회는 없었지만 다음에 INotifyPropertyChanged에 대한 큰 요구 사항으로 프로젝트를 설정할 때 컴파일 타임에 코드를 주입 하는 Postsharp 속성을 작성하려고합니다 . 다음과 같은 것 :
[NotifiesChange]
public string FirstName { get; set; }될 것입니다:
private string _firstName;
public string FirstName
{
   get { return _firstname; }
   set
   {
      if (_firstname != value)
      {
          _firstname = value;
          OnPropertyChanged("FirstName")
      }
   }
}이것이 실제로 작동하는지 확실하지 않으며 앉아서 시도해야하지만 왜 그런지 모르겠습니다. 하나 이상의 OnPropertyChanged를 트리거해야하는 상황에 대해 일부 매개 변수를 수락해야 할 수도 있습니다 (예를 들어 위 클래스에 FullName 속성이있는 경우).
현재 Resharper에서 사용자 정의 템플릿을 사용하고 있지만 그로 인해 모든 속성이 너무 길어지고 있습니다.
아, 빠른 Google 검색 (이 글을 작성하기 전에 수행해야했던 것)은 적어도 한 사람이 여기 전에 이와 같은 작업을 수행했음을 보여줍니다 . 내가 생각한 바가 아니라 이론이 훌륭하다는 것을 보여줄만큼 충분히 가까웠다.
