【问题标题】:Multiple types as single generic parameter多种类型作为单个泛型参数
【发布时间】:2017-05-16 20:14:26
【问题描述】:

有一个抽象类和接口:

public abstract class Foo
{
    public void DoFoo();
}
public interface IBar
{
     void DoBar();
}

我有多个继承自 Foo 的类,但并非所有类都实现了 IBar。我可以声明将被 Foo 和 IBar 约束的泛型类,如下所示:

public class Test<T> where T : Foo, IBar
{
    public List<T> ListOfFooThatImplementsIBar;
}

但我想定义一个简单的集合,它将被限制为 Foo 和 IBar,如下所示:

List<Foo and IBar> myList = new List<Foo and IBar>();

有没有办法在 C# 中很好地做到这一点?

【问题讨论】:

  • 您为什么想要一个彼此没有任何关系(常用方法/属性)的事物的列表?您不妨使用List&lt;object&gt;
  • @itsme86 好点 - 我不确定这里的用例是什么。 T 只能作为IFoo(以我的示例)访问,它什么都没有。如果 Valery 想确定 TFoo 还是 IBar,他们将不得不 safe-cast 并检查 null。
  • 您可能需要使用MyList&lt;T&gt; : IList&lt;T&gt; where T : Foo, IBar 之类的东西,并使用List&lt;T&gt; 作为实现细节。
  • 没关系。 @EricLippert 澄清了他对其中一个答案的评论中的意图。我把这个问题解释为关于联合类型。
  • 对不起,我迷路了。如果你真的想要这个,为什么不能像class ListFooAndIBar&lt;T&gt; : List&lt;T&gt; where T : Foo, IBar { } 那样子类List&lt;T&gt;?我可以理解为什么在语言中拥有它是一个很好的功能,但我没有理解为什么你想要的东西至少在实际中是不可能的?

标签: c# generics


【解决方案1】:

有没有办法在 C# 中很好地做到这一点?

没有。

您想要的功能称为“intersection types”。 C# 仅支持“where”子句中的交集类型。这总是让我觉得有点奇怪。

也很奇怪:我每天都与 C# 泛型类型系统的设计者交谈,但我从未想过要问他是什么设计原则导致只在一个地方使用交集类型。也许我明天会解决这个问题!

许多语言或多或少地支持交集类型——我想到了 Hack 和 Flow。有趣的是,它们都使用基于流的类型。交集和联合类型在很多方面都非常适合基于流的类型。

【讨论】:

  • 谢谢埃里克。您的回答非常直截了当而且很有帮助!
  • @Eric Lippert,OT,C# 泛型类型系统的设计者是谁?他也搬到FB了吗? ;)
  • @SolutionYogi:安德鲁·肯尼迪,是的;我们一起开发 Hack。
【解决方案2】:

正如@EricLippert 回答的那样,没有办法完全按照我的意愿进行操作。这个问题有几种解决方法:

  1. 为 Foo 和 IBar 创建通用接口(如果 Foo 类是第三方类并且您不能影响它们的来源,如我的情况,则可能不适用)
  2. 使用原始列表作为 List 并在需要时执行运行时强制转换(这可能会降低性能)。

我选择最适合我需要的第三个:

public List<(Foo, IBar)> ListOfFooThatImplementsIBar;

public void Add<T>(T item) where T : Foo, IBar { ListOfFooThatImplementsIBar.Add((item, item)); }

所以当我需要与 Foo 交互时,我可以使用 Item1,Item2 与 IBar 交互。 希望我的回答有帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-28
    • 1970-01-01
    • 1970-01-01
    • 2018-05-18
    • 2016-11-14
    相关资源
    最近更新 更多