自定义(派生)List<T>

6

随意装备你的枪支并瞄准,但我想了解为什么你不应该这样做。

我创建了一个自定义类,旨在替换任何List实例(我用它来更新它们背后的XML对象):

public class ListwAddRemove<T> : List<T> {
    public event EventHandler<ListModifyEventArgs> OnAdd;
    public event EventHandler<ListModifyEventArgs> OnRemove;

    new public void Add(T o) {
        base.Add(o);

        if (OnAdd != null) {
            OnAdd(this, new ListModifyEventArgs(o));
        }
    }

    new public void Remove(T o) {
        base.Remove(o);

        if (OnRemove != null) {
            OnRemove(this, new ListModifyEventArgs(o));
        }
    }
}

这个想法是,每当我向这个列表中添加或删除一个项目时,我的绑定事件就会触发,我可以自动处理背后的XML。

到目前为止,这个方法非常好用,效果很好。

但是,如何处理对象.ToList()和我的派生版本之间的转换呢?

许多人都说你应该从Collection中派生...为什么呢?


11
你听说过ObservableCollection吗?它是一种特殊的集合类型,可用于WPF和WinRT应用程序中的数据绑定。你可以通过以下链接了解更多信息:http://msdn.microsoft.com/en-au/library/ms668604(v=vs.110).aspx 和 https://dev59.com/7E7Sa4cB1Zd3GeqP69JG - aybe
我正在使用 Windows Forms .Net 3.5。 - user1830285
使用new修饰符来隐藏基类成员从来不是一个好主意。如果你真的想从List<>派生,给你的方法一些新名称,比如AddAndRaiseEvent或类似的名称。然而,List<>类并不是为这种用途而设计的。还有其他类提供更多的virtual成员,旨在在继承它们时提供帮助。 - Jeppe Stig Nielsen
@user1830285 ObservableCollection 在 .Net 3.5 中仍然可用,并且可以与 Windows Forms 一起使用,它只是实现了 INotifyCollectionChangedINotifyPropertyChanged 接口的集合。请参阅 https://dev59.com/O2855IYBdhLWcg3wilCD 以获取更多信息。 - user692942
2个回答

7
您应该从Collection<T>派生,因为它的设计允许您重写InsertItemRemoveItem以添加自定义行为,比如您正在做的(还有SetItem,用于在更改现有项目时添加自定义行为)。
因此,它可以被用作IList<T>,并且任何插入/删除操作都将自动使用自定义功能。
在您的情况下,任何转换为IList<T>或基类List<T>的人都将绕过您的自定义添加/删除功能。 Collection<T>还提供了一个构造函数来包装现有列表。 您可以从派生类中公开此函数,以包装由Enumerable<T>.ToList()生成的列表。 更新

请问公开构造函数的语法是什么?

非常简单:
public class ListwAddRemove<T> : Collection<T>
{
    public ListwAddRemove<T>()
    {
    }

    public ListwAddRemove<T>(IList<T> list) : base(list)
    {
    }

    ... implementation of overrides for InsertItem, SetItem, RemoveItem ...
}

然后按以下方式使用:

IList<SomeType> list = ....ToList();
ListwAddRemove<SomeType> myList = new ListwAddRemove<SomeType>(list);

任何将类型转换为 IList<T> 接口的人都将失去新功能,但是将类型转换为基类 List<T> 的人也会失去(就像 MartinStettner 的回答中所述)。 - Jeppe Stig Nielsen
你可以从派生类中公开这个方法,以包装生成的列表...请问公开构造函数的语法是什么?我喜欢这个实现。 - user1830285
没问题,我懂了:public ListwAddRemove(List<T> incomingList) : base(incomingList) { } - user1830285

2
首先,
void DoSomeAddingToList(List<int> list) {
  list.Add(1);
}

var list = new ListwAddRemove<int>();
DoSomeAddingToList(list);

不会触发事件。如果你不是唯一使用这个类,这可能会导致奇怪的效果。 List<T>AddRemove定义了非常特定的行为(因为它是一个具体类),用户可能依赖于这种行为。
我认为这通常适用于使用new修饰符,因此应该谨慎使用这种语言特性,特别是在公共方法上。
正如其他人所提到的,通过委托/聚合来实现IList<T>可能是更好的选择。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接