如何强制Activator创建的实例调用子类的Shadowed Add方法?
问题描述
我定义了继承自ObservableCollection<MyClassItem>的CustomCollection类,使用new关键字隐藏Add方法并添加自定义逻辑:
class MyClassItem { ... } class CustomCollection : ObservableCollection<MyClassItem> { public CustomCollection(){} public new void Add(MyClassItem item) { //...自定义处理逻辑 base.Add(item); } }
同时实现了泛型复选列表类MyGenericCheckList<T>,其GetSelectedItemsAsCollection<CT>方法通过Activator.CreateInstance<CT>创建指定类型的集合,并添加选中项:
class GenericCheckListItem<T> { //...自定义实现 public T Item {get; set;} } class MyGenericCheckList<T> : ObservableCollection<GenericCheckListItem<T>> { //...自定义实现 public CT GetSelectedItemsAsCollection<CT>() where CT: ICollection<T>, new() { CT collection = Activator.CreateInstance<CT>(); foreach(var item in this) { collection.Add(item.Item); } return collection; } }
使用示例:
MyGenericCheckList<MyClassItem> cList = new MyGenericCheckList<MyClassItem>(); // ...添加数据并选择项目 var myColl = cList.GetSelectedItemsAsCollection<CustomCollection>();
问题:尽管collection实例是CustomCollection类型,但调用的Add方法是基类ObservableCollection的实现,而非自定义的隐藏方法,导致自定义的簿记逻辑未执行。请问如何强制调用该自定义方法?若不可行,有其他实现思路吗?
解决思路
1. 类型转换调用(局限性大)
在GetSelectedItemsAsCollection方法中,判断创建的集合是否为CustomCollection类型,若是则转换为该类型后调用其Add方法,否则使用接口的Add。但这种方式会让方法与CustomCollection强耦合,失去泛型的通用性:
public CT GetSelectedItemsAsCollection<CT>() where CT: ICollection<T>, new() { CT collection = Activator.CreateInstance<CT>(); if (collection is CustomCollection customColl) { foreach(var item in this) { customColl.Add(item.Item); } } else { foreach(var item in this) { collection.Add(item.Item); } } return collection; }
2. 重写ObservableCollection核心方法(推荐)
ObservableCollection<T>的Add方法最终会调用InsertItem虚方法,因此不要用new隐藏Add,而是重写InsertItem来注入自定义逻辑。这样无论通过子类Add、基类Add还是ICollection<T>接口调用Add,都会触发自定义逻辑:
class CustomCollection : ObservableCollection<MyClassItem> { public CustomCollection(){} protected override void InsertItem(int index, MyClassItem item) { //...自定义处理逻辑 base.InsertItem(index, item); } }
这种方式符合ObservableCollection的设计规范,避免了方法隐藏带来的调用歧义问题。
3. 自定义接口+泛型约束
如果一定要保留new的Add方法,可以定义包含自定义Add的接口,让CustomCollection实现它,再修改泛型方法的约束,直接调用自定义Add:
public interface ICustomAdd<T> { void Add(T item); } class CustomCollection : ObservableCollection<MyClassItem>, ICustomAdd<MyClassItem> { public CustomCollection(){} public new void Add(MyClassItem item) { //...自定义处理逻辑 base.Add(item); } } // 修改泛型方法约束 public CT GetSelectedItemsAsCollection<CT>() where CT: ICollection<T>, ICustomAdd<T>, new() { CT collection = Activator.CreateInstance<CT>(); foreach(var item in this) { collection.Add(item.Item); } return collection; }
但这种方式要求所有目标集合类型都实现ICustomAdd<T>接口,通用性不如第二种方案。
内容的提问来源于stack exchange,提问作者Kikanye

