使用两个属性公开相同的集合集合

时间:2017-02-22 15:16:47

标签: c# .net generics covariance typing

注意:请不要在当前状态下重视此问题。一旦我能够解决我的潜在问题,我就会意识到我会很难重新解释这个问题,以真正反映出它的动机和决议是什么。 Anwyay,我将在接下来的几天里尝试对其进行改写,以便它对未来的访问者有用,并且回答者可能有机会调整答案。即使是我的自动回答也没有反映出这个问题,所以它对社区有用......

假设我有一个这样的界面:

public interface IHasMany<T>
{
      ISet<T> Items { get; }
}

一个类实现如下:

public class X : IHasMany<IWhatever>
{
     public ISet<Whatever> Whatevers { get; } = new HashSet<Whatever>();
     ISet<IWhatever> IHasMany<IWhatever>.Items { get; }
}

由于集合泛型类型不能协变(我理解为什么它被设计阻止的背景),所以没有简单的路径来公开一组一些给定的接口实现和一组同时键入接口的相同实现。

为了找到一个理想情况下我不需要实现某种同步或更改跟踪来维护两个不同集合的解决方案,我正在摸不着头脑......

请注意,IHasMany<T>.Items必须仍然可写,否则就像将其键入IEnumerable<IWhatever>并继续前进一样简单......

1 个答案:

答案 0 :(得分:6)

C#不会阻止您的设备变得协变,因为C#团队并不打算弄清楚如何实现它。相反,它在C#中是不可能的,因为它在概念上是不可能的。您根本无法将ISet<Whatever>视为ISet<IWhatever>,因为您可以向不属于ISet<IWhatever>类型的Whatever添加项目,如果实际对象是ISet<Whatever>,则不允许添加非Whatever类型的项目。

你可以拥有IReadOnlySet<IWhatever>类型的属性并使其具有协变性,但是由于你想拥有一个可变集,所以没有办法让它工作。您必须将实际的基础集合设为一组IWhatever个对象,或者X实现IHasMany<Whatever>而不是IHasMany<IWhatever>,因为它只是前者的合同你真的希望它能实现,而不是后者。