So I have been struggling around this for some time now.
I have some SuperAwesome™ abstract classes which implement various commonly used snippets of code.
This one implement the INotifyPropertyChanged quite nicely and I don't want to cut and paste it around in my code:
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
}
This other one does something else:
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
}
...And so on.
While I can inherit a class from either of these, I can't inherit from more than one. I know the "common" solution for c# lacking multiple inheritance is to use interfaces but I have yet to find a way to get the actual code written only once and not cut-and-pasted all around. I've looked briefly at extension methods, but the result looked like a mess.. I also though about macros but c# don't get those either..
So my question is how do I prevent cut-and-pasting those snippets in all my children classes and make modification a nightmare...
EDIT: I have given a try at composition and... wow, I feel let down by C# for the first time. If composition is the best way to achieve this, there is something broken. Am I missing something?
Here is a try at compositing INotifyPropertyChanged with some added benefits; I cannot figure out how to get rid of the OnPropertyChanged's code cut and paste; also interfaces forces everything to be public...:
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
}
}
}
Unless I am missing something or it could be done better I don't really expect an answer here... consider this my final /rant on c# missing multiple inheritance.