Lets say I have two interfaces ISomeInterface and ISomeInterface<T> and ISomeInterface<T> inherites from ISomeInterface.
Now if we have to classes Someclass and SomeClass<T> how can we implement composition over inheritance? Which class should have instance of another class?
public interface ISomeInterface
{
string Name {get;}
}
public interface ISomeInterface<T> : ISomeInterface
{
string ResultMessage{get;}
}
public class SomeClass : ISomeInterface
{
public string Name
{
get{return this.GetType().Name;
}
}
public class SomeClass<T> ISomeInterface<T>
{
ISomeInterface _someclassinstance = new SomeClass;
public string Name
{
get{return _someclassInstance.Name;
}
public string Caption
{
get{return "Demo Caption";}
}
}
This will not work as when I call Name property on instance of generic version of class it will return SomeInterface not derived class name.
I would like to know if it is good implementation or Non-Generic version should have instance of Generic opposite of what I have done so far?
public abstract class ViewModelBase : NotificationObject, IViewModel
{
private IViewModel _parent;
private string _title;
private bool _isBusy;
private bool _isDitry;
#region Viewmodel Initialization steps
/// <summary>
/// Initializes a new instance of the <see cref="ViewModelBase"/> class.
/// </summary>
internal protected ViewModelBase()
{
ResolveDependencies();
Load();
}
/// <summary>
/// Exposes a way for external users to pass a boxed payload
/// to this view model for initialization purposes.
/// Inheritors can override this method to perform specific
/// initialization and validation operations depending on the
/// payload sent from the outside.
/// </summary>
/// <param name="payload">
/// Represents the boxed payload the view model uses
/// for initialization purposes.
/// </param>
public virtual void Initialize(object payload)
{
}
/// <summary>
/// Loads the view model.
/// </summary>
private void Load()
{
BeforeLoad();
OnLoad();
}
/// <summary>
/// Gives inheritors the opportunity to perform an operation before the view model loads.
/// </summary>
protected virtual void BeforeLoad()
{
}
/// <summary>
/// Gives inheritors the opportunity to perform specific operations when the view model loads for the first time.
/// </summary>
protected virtual void OnLoad()
{
SetupEvents();
}
/// <summary>
/// Registers listeners for all events in which the ViewModel is interested in.
/// </summary>
protected virtual void SetupEvents()
{
}
/// <summary>
/// Resolves the dependencies for this view model.
/// </summary>
private void ResolveDependencies()
{
BeforeResolveDependencies();
EventAggregator = ServiceLocator.Current.GetInstance<IEventAggregator>();
OnResolveDependencies();
}
/// <summary>
/// Gives inheritors the opportunity to perform an operation before the dependencies are resolved.
/// </summary>
protected virtual void BeforeResolveDependencies()
{
}
/// <summary>
/// Gives inheritors the opportunity to resolve dependencies of their own.
/// </summary>
protected virtual void OnResolveDependencies()
{
}
/// <summary>
/// Event handler that notifies the new children of the parent
/// view model they live in and removes the parent when they are
/// removed from the collection.
/// </summary>
/// <param name="sender">Child view model rising the event.</param>
/// <param name="e">Changes made to the collection.</param>
protected void ChildCollectionChangedHandler(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (var item in e.NewItems)
{
((ViewModelBase)item).Parent = this;
}
}
if (e.OldItems == null) return;
foreach (var item in e.OldItems)
{
((ViewModelBase)item).Parent = null;
}
}
#endregion
#region Members of IViewModel
/// <summary>
/// Gets the title.
/// </summary>
public string Title
{
get { return _title ?? (_title = GetType().Name); }
protected set
{
_title = value;
RaisePropertyChanged(() => Title);
}
}
/// <summary>
/// Gets or sets a value indicating whether the ViewModel is busy.
/// </summary>
/// <value><see langword="true"/> if the ViewModel is busy; otherwise, <see langword="false"/>.</value>
public bool IsBusy
{
get { return _isBusy; }
protected set
{
_isBusy = value;
RaisePropertyChanged(() => IsBusy);
}
}
/// <summary>
/// Gets or sets a value indicating whether this instance is dirty.
/// </summary>
/// <value>
/// <c>true</c> if this instance is dirty; otherwise, <c>false</c>.
/// </value>
public bool IsDirty
{
get { return _isDitry; }
set
{
_isBusy = value;
RaisePropertyChanged(() => IsDirty);
}
}
/// <summary>
/// Gets or sets the view for which this instance is set as DataContext.
/// </summary>
/// <value>
/// The view.
/// </value>
public IView View { get; set; }
/// <summary>
/// Gets the parent ViewModel holding this instance as
/// childe ViewModel collection item.
/// </summary>
public IViewModel Parent
{
get { return _parent; }
set
{
_parent = value;
RaisePropertyChanged(() => Parent);
}
}
#endregion
/// <summary>
/// Get CurrentInstance of EventAggregator
/// </summary>
private IEventAggregator EventAggregator { get; set; }
/// <summary>
/// Gets the dispatcher. Works at run-time and test-time.
/// </summary>
/// <value>The dispatcher.</value>
protected static Dispatcher Dispatcher
{
get { return Application.Current != null ? Application.Current.Dispatcher : Dispatcher.CurrentDispatcher; }
}
/// <summary>
/// Resolves this instance for specific type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
protected static T Resolve<T>()
{
try
{
return ServiceLocator.Current.GetInstance<T>();
}
catch (Exception)
{
return default(T);
}
}
/// <summary>
/// Resolves all instances of specific type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
protected static IEnumerable<T> ResolveAll<T>()
{
return ServiceLocator.Current.GetAllInstances<T>();
}
/// <summary>
/// Registers for specific event inside system event providing some filter parameters.
/// </summary>
/// <typeparam name="TEvent">The type of the event.</typeparam>
/// <param name="onEvent">The on event.</param>
/// <param name="filter">The filter.</param>
protected void RegisterForEvent<TEvent>(Action<TEvent> onEvent, Predicate<TEvent> filter = null) where TEvent : class
{
EventAggregator.Subscribe<TEvent>(onEvent, ThreadOption.PublisherThread, false, filter);
}
/// <summary>
/// Broadcasts the specified event object.
/// </summary>
/// <typeparam name="TEvent">The type of the event.</typeparam>
/// <param name="eventObject">The event object.</param>
protected void Broadcast<TEvent>(TEvent eventObject) where TEvent : class
{
EventAggregator.Publish(eventObject);
}
}
this is thi complete implementation of IViewModel base class and
public abstract class ViewModelBase<TValidator> : ViewModelBase,IViewModel<TValidator>, IDataErrorInfo
where TValidator : IValidator, new()
{
private bool _islValid;
readonly IValidator _validator = new TValidator();
/// <summary>
/// Get Validation processor for ViewmodelInstance
/// </summary>
/// <value>
/// The Validator.
/// </value>
public TValidator Validator
{
get { return (TValidator) _validator; }
}
public bool IsValid
{
get
{
_islValid = SelfValidate().IsValid;
return _islValid;
}
private set
{
_islValid = value;
RaisePropertyChanged(() => IsValid);
}
}
// Implementation for validation
}
Here I posted source for both classes. and there are N number of differenc interfaces and classes which all need to derive either from Generic or Non-Generic version of these classes. put properties available in IViewmodel should be available on every derived class and protected methods and properties needs to be kept as well
Regarding the composition, generic version needs to use the non-generic version.
You can’t go the opposite way, because the generic version of the class is the strongly typed one, which means it contains more compile time detail than the non-generic version. There would be no way to pass the required types to the inner generic class from the non-generic class.
As of the
Nameproperty, it actually does exactly what it is supposed to do, return theNameof theSomeClasstype.Edit:
If you need a way to always return the name of the current type, then there is many ways how you could go about this. You could make a normal or generic helper method for this, or for example you could make an extension method for the
ISomeInterfacetype and use it instead of theNameproperty:But all you will achieve is just to make a shortcut to the
GetType().Name, as all the types have these already.I don’t see much value in this solution, at least in the given example with the type name.
Also this is in no way related to generics vs non-generics or all the other stuff mentioned.