所以我一直在努力解决这个问题。
我有一些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
}
......等等。
虽然我可以从其中任何一个继承一个类,但我不能从多个继承。我知道&#34;常见&#34;缺少多重继承的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#缺少多重继承的最终/咆哮。
答案 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 Design Patterns”一书,参见“设计鸭子行为”,该示例以非常明确的方式解释了这一点:Head First Design Patterns
答案 1 :(得分:1)
你应该问问自己为什么你需要InotifyPropertyChanhed和Disposable Singleton。
在我看来,你有一个必须继承InotifyPropertyChanged的视图模型。但是我不确定它是否也应该是一次性的单例...我建议你使用该单例的组合,这意味着你的视图模型将具有该sigleton的属性,该属性将是所有app中的共享单个对象< / p>