假设我有两个接口ISomeInterface
,ISomeInterface<T>
和ISomeInterface<T>
继承自ISomeInterface
。
现在,如果我们必须使用类Someclass
和SomeClass<T>
,我们如何实现组合而不是继承?哪个类应该有另一个类的实例?
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";}
}
}
当我在类的泛型版本的实例上调用Name
属性时,它将返回SomeInterface
而不是派生类名。
我想知道它是好的实现还是Non-Generic版本应该具有与我迄今为止所做的相反的Generic实例?
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);
}
}
这是IViewModel基类和
的完整实现 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
}
这里我发布了这两个类的源代码。并且有N个不同的接口和类,它们都需要从这些类的通用版本或非通用版本派生。 IViewmodel中的put属性应该在每个派生类上都可用,并且需要保留受保护的方法和属性
答案 0 :(得分:1)
关于组合,通用版本需要使用非通用版本。
你不能采用相反的方式,因为类的通用版本是强类型的,这意味着它包含比非泛型版本更多的编译时细节。没有办法将所需类型从非泛型类传递给内部泛型类。
从Name
属性开始,它实际上完成了它应该做的事情,返回Name
类型的SomeClass
。
修改强>
如果您需要一种始终返回当前类型名称的方法,那么有很多方法可以解决这个问题。您可以为此创建普通或通用帮助方法,或者例如,您可以为ISomeInterface
类型创建扩展方法,并使用它而不是Name
属性:
public static class SomeInterfaceExtensions
{
// Extension
public static string GetName(this ISomeInterface some)
{
return some.GetType().Name;
}
}
// Usage
var some = new SomeClass<int>();
var name = some.GetName();
但你所要达到的只是制作GetType().Name
的快捷方式,因为所有类型都有。{/ p>
我在这个解决方案中看不到多少价值,至少在给定的类型名称示例中是这样。
此外,这与仿制药与非仿制药或所有其他提及的东西无关。