2016-03-06 93 views
0

所以我一直在努力解決這個問題一段時間了。如何防止C#中的代碼重複多個繼承

我有一些SuperAwesome™抽象類實現各種常用的代碼片段。

這一個實現INotifyPropertyChanged相當不錯,我不希望削減它在我的代碼粘貼左右:

public abstract class INotifyPropertyChangedImplementor : INotifyPropertyChanged 
{ 
    #region INotifyPropertyChanged Support 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     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; 
    } 
    #endregion 
} 

這另一個則別的東西:

public abstract class IDisposableSingletonImplementor<T> : IDisposable where T : new() 
{ 
    #region Disposable singleton 
    public static T Instance 
    { 
     get 
     { 
      if (_Instance == null) 
      { 
       _Instance = new T(); 
      } 
      return _Instance; 
     } 
    } 
    protected static T _Instance = default(T); 
    public static void DisposeInstance() 
    { 
     ((IDisposable)_Instance)?.Dispose(); 
     _Instance = default(T); 
    } 
    public static bool IsInstanceCreated 
    { 
     get 
     { 
      return _Instance != null; 
     } 
    } 
    #endregion 
    #region IDisposable Support 
    protected virtual void Dispose(bool disposing) 
    { 
     if (!disposedValue) 
     { 
      if (disposing) 
      { 
       DisposeManaged(); 
      } 
      DisposeUnmanaged(); 
      // TODO: set large fields to null. 
      disposedValue = true; 
     } 
    } 
    private bool disposedValue = false; 
    public void Dispose() 
    { 
     // Do not change this code. Put cleanup code in Dispose(bool disposing) above. 
     Dispose(true); 
     //only enable this is destructor is present 
     //GC.SuppressFinalize(this); 
    } 
    protected abstract void DisposeManaged(); 
    protected abstract void DisposeUnmanaged(); 
    #endregion 
} 

.. 。等等。

雖然我可以繼承其中任何一個類,但我不能從多個繼承。我知道缺乏多重繼承的c#的「常用」解決方案是使用接口,但我還沒有找到一種方法來只寫一次實際的代碼,而不是全部剪切和粘貼。我簡單地看了一下擴展方法,但結果看起來像一團糟..我也雖然關於宏,但C#沒有得到那些..

所以我的問題是如何防止剪切和粘貼在我所有的少兒班的片段,並進行修改的噩夢......

編輯:我已經給在組成一個嘗試,...哇,我感到失望的C#首次。如果構圖是實現這一目標的最佳途徑,那麼就會有某些東西被破壞。我錯過了什麼嗎?

這是一個嘗試合成INotifyPropertyChanged與一些額外的好處;我無法弄清楚如何擺脫OnPropertyChanged的代碼剪切和粘貼;接口也一切力量是公共...:

public interface INotifyPropertyChangedEx : INotifyPropertyChanged 
{ 
    //i dont want these public but i want to force their implementation in child classes... 
    bool SetField<T>(ref T field, T value, string propertyName); 
    void OnPropertyChanged(string propertyName); 
} 
public class INotifyPropertyChangedBehavior : INotifyPropertyChangedImplementor 
{ 

} 
public abstract class INotifyPropertyChangedImplementor : INotifyPropertyChangedEx 
{ 
    //this is the code i dont want to replicate 
    #region INotifyPropertyChanged Support 
    public event PropertyChangedEventHandler PropertyChanged; 
    public void OnPropertyChanged([CallerMemberName] string propertyName = null) //public yuck 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
    public bool SetField<T>(ref T field, T value, string propertyName) //public yuck 
    { 
     if (EqualityComparer<T>.Default.Equals(field, value)) return false; 
     field = value; 
     OnPropertyChanged(propertyName); 
     return true; 
    } 
    #endregion 
} 


//so try at imlpementation.. 
public class Test1 : INotifyPropertyChangedImplementor 
{ 
    //wow such easy implementation, nothing to do!! 

    //some actual data 
    private string _Name; 
    public string Name 
    { 
     get 
     { 
      return _Name; 
     } 
     set 
     { 
      SetField(ref _Name, value, nameof(Name)); 
     } 
    } 
} 
public class Test2 : INotifyPropertyChangedEx 
{ 
    public event PropertyChangedEventHandler PropertyChanged;//created from interface 
    //the composition behavior object 
    private INotifyPropertyChangedBehavior NotifyPropertyChangedBehavior = new INotifyPropertyChangedBehavior(); 
    public bool SetField<T>(ref T field, T value, string propertyName)//created from interface 
    { 
     return NotifyPropertyChangedBehavior.SetField(ref field, value, propertyName);//actual code reuse, yay 
    } 
    public void OnPropertyChanged(string propertyName)//created from interface 
    { 
     //cannot reuse code here, other classes wont register my internal NotifyPropertyChangedBehavior.PropertyChanged... 
     //composition fail miserably for events, so this is a cut and paste 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    //some actual data 
    private string _Name; 
    public string Name 
    { 
     get 
     { 
      return _Name; 
     } 
     set 
     { 
      SetField(ref _Name, value, nameof(Name)); 
     } 
    } 
} 
public class main 
{ 
    //both Test1 (inherited) and Test2 (composited) classes should be usable in the same exact way 
    Test1 test1 = new Test1(); 
    Test2 test2 = new Test2(); 
    public main() 
    { 
     test1.PropertyChanged += Test1_PropertyChanged; 
     test2.PropertyChanged += Test2_PropertyChanged; 
    } 
    private void Test1_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     if (e.PropertyName == nameof(test1.Name)) 
     { 
      //react 
     } 
    } 
    private void Test2_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     if (e.PropertyName == nameof(test2.Name)) 
     { 
      //react 
     } 
    } 
} 

除非我失去了一些東西,或者它可以做更好,我從來沒有真正想過的答案在這裏......考慮在C#這是我最後的/咆哮失蹤多重繼承。

+4

使用組合,而不是繼承。 – Dai

+0

謝謝,我會試試看。 –

回答

2

您可以創建多個類,實現所有必需行爲的代碼(例如NotifyPropertyChangedBehaviour,DisposableSingletonBehaviour,EditableObjectBehaviour),然後將所有需要的行爲的實例包含到每個類(組合)中。然後,您需要爲您的類實現的接口創建代理方法,並將該調用傳遞給相關的行爲類。 這樣你的類可以實現無限數量的行爲和接口。

例如:

class myClass : IMayDoSomething, IMayDoSomethingElse 
{ 
    DoSomethingBehaviour m_doSomethingBehaviour; 
    public void DoSomething() 
    { 
     m_doSomethingBehaviour.DoSomething(); 
    } 

    DoSomethingElseBehaviour m_doSomethingElseBehaviour; 
    public void DoSomethingElse() 
    { 
     m_doSomethingElseBehaviour.DoSomethingElse(); 
    } 

} 

public class DoSomethingBehaviour 
{ 
    public void DoSomething() 
    { 
     // All the code of the method which appears just once, no 
     // copy-paste in classes implementing the behaviour 
    } 
} 
... 

您可能會看到一些例子在這篇文章中:Simulating Multiple Inheritance in C#: Part I
而且還看到了「Head First設計模式」一書中,看到了「設計鴨子行爲」的例子解釋了以非常明確的方式指出:Head First Design Patterns

+0

非常感謝,這是我需要的答案。 –

1

你應該問自己爲什麼你需要InotifyPropertyChanhed和一次性Singleton。

正如我看到它,你有一個視圖模型,它必須繼承InotifyPropertyChanged。然而,我不確定它應該是一次性單身...我建議你使用這個單例的組合,這意味着你的視圖模型將具有該sigleton的屬性,該屬性將成爲跨所有應用的共享單個對象

+0

這裏的關鍵不是設計模式應該使用什麼,而是如何編寫它們只有一次,並且在沒有剪切和粘貼的情況下使用它們,多重繼承是非常好的事情。當你們回答我時,我認爲構圖是最好的實現這個方法 –