使用自定义集合类时接口不再起作用

发布于 2024-10-18 03:39:08 字数 357 浏览 0 评论 0原文

我创建了一个类 MonitoredCollection,它基本上封装/模仿 List,但允许我在某些调用上触发事件。

但是现在,只要有一个采用 MonitoredCollection 的参数,其中 T 是一个接口,我就无法再传递一个 MonitoredCollection 其中 T 是实现该接口的类,就像我可以使用一个列表

我一直认为接口是一种语言“功能”,因此我不需要再实现任何东西来支持这一点,那么我错过了什么?

编辑:抱歉,我在这个问题上犯了一个错误,因为 João 正确地指出 List 在这种情况下从未起作用,所以问题就是没有这个!

I have created a class, MonitoredCollection<T>, that basically encapsulates/mimics List but allows me to fire events on certain calls.

Now however, whereever there is a parameter that takes a MonitoredCollection, where T is an Interface, I can no longer pass a MonitoredCollection<T> where T is a class that implements that interface, like I could with a List.

I always thought that interfaces were a language 'feature' and therefore I don't need to implement anything more to support this, so what have I missed?

EDIT: Sorry, I made a mistake in that question, as João correctly pointed out List never worked in this instance so the question is as it stands without that!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

俏︾媚 2024-10-25 03:39:08

假设您有一个 MonitoredCollection 实例,并且您希望将其视为 MonitoredCollection 实例,其中 SomeObject 实际上实现了ISomeInterface。这不会对从集合中检索项目产生任何问题,因为 SomeObject 类型的对象可以转换为接口类型 ISomeInterface

但是,对于集合中修改集合的所有方法(例如为索引分配新值或将新项目插入集合中的方法),此转换会产生一整套问题。我假设您的 MonitoredCollection 实例具有诸如 Add(SomeObject obj) 之类的方法,该方法会将新对象插入到集合中。转换后,此方法的签名将是 Add(ISomeInterface obj)。这似乎是有道理的,但并非所有 ISomeInterface 对象都必然是 SomeObject 实例。

由于转换后的对象将允许对原始对象不允许的集合进行操作,因此运行时将不允许此转换。 C# 4.0 引入了协变和逆变来明确说明什么对于这种类型的强制转换是有效的,您可以研究它们以尝试解决此问题。但是,您实际上只能幸运地获得集合的只读版本(想想 List.AsReadOnly())。

Suppose you have a MonitoredCollection<SomeObject> instance, and you want to treat it as a MonitoredCollection<ISomeInterface> instance where SomeObject does in fact implement ISomeInterface. This does not create any problems for retrieving items from the collection, since object of type SomeObject can be converted to the interface type ISomeInterface.

However, for all the methods on your collection which modify the collection, such as those that assign a new value to an index, or insert a new item into the collection, this cast has created a whole suite of issues. I'd assume your MonitoredCollection<SomeObject> instance would have a method such as Add(SomeObject obj), which would insert a new object into the collection. After the cast, the signature on this method would be Add(ISomeInterface obj). This seems to make sense, but not all ISomeInterface objects are NECESSARILY SomeObject instances.

Because the casted object will allow operations on the collection that the original object wouldn't allow, the runtime won't allow this cast. C# 4.0 introduced covariance and contravariance to explicitly state what is valid for casts of this type, you can look into them for trying to solve this issue. However, you're really only going to have luck with a read only version of your collection (think List<T>.AsReadOnly()).

九厘米的零° 2024-10-25 03:39:08

不幸的是,你也不能用列表来做到这一点。编译器仍然无法转换类型。您需要使用通用方法。参见下面的代码:

class Test
{
    void DoTest()
    {
        MonitoredList<IInterface> mlist1 = new MonitoredList<Inherited>(); //Error
        MonitoredList<Inherited> mlist2 = new MonitoredList<Inherited>();
        DoSomething1(mlist2); //Error converting MonitoredList<Inherited> to MonitoredList<IInterface>

        MonitoredList<IInterface> list1 = new MonitoredList<Inherited>(); //Error
        MonitoredList<Inherited> list2 = new MonitoredList<Inherited>();
        DoSomething2(list2); //Error converting List<Inherited> to List<IInterface>

        DoSomething3<Inherited>(mlist2); //Works fine
        DoSomething3(mlist2); //<Inherited> is redundant
    }

    void DoSomething1(List<IInterface> list)
    { }

    void DoSomething2(MonitoredList<IInterface> list)
    { }

    //Generic method
    void DoSomething3<T>(MonitoredList<T> list) where T : IInterface
    { }
}

interface IInterface { }

class Inherited : IInterface { }

class MonitoredList<T> { }

Unfortunately, you can't do that with a list either. The compiler still cannot convert the types. You need to use a generic method. See code below:

class Test
{
    void DoTest()
    {
        MonitoredList<IInterface> mlist1 = new MonitoredList<Inherited>(); //Error
        MonitoredList<Inherited> mlist2 = new MonitoredList<Inherited>();
        DoSomething1(mlist2); //Error converting MonitoredList<Inherited> to MonitoredList<IInterface>

        MonitoredList<IInterface> list1 = new MonitoredList<Inherited>(); //Error
        MonitoredList<Inherited> list2 = new MonitoredList<Inherited>();
        DoSomething2(list2); //Error converting List<Inherited> to List<IInterface>

        DoSomething3<Inherited>(mlist2); //Works fine
        DoSomething3(mlist2); //<Inherited> is redundant
    }

    void DoSomething1(List<IInterface> list)
    { }

    void DoSomething2(MonitoredList<IInterface> list)
    { }

    //Generic method
    void DoSomething3<T>(MonitoredList<T> list) where T : IInterface
    { }
}

interface IInterface { }

class Inherited : IInterface { }

class MonitoredList<T> { }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文