【问题标题】:Are Lower Bounded Wildcards possible in C#?C# 中是否可以使用下界通配符?
【发布时间】:2019-08-28 10:03:21
【问题描述】:

我是一名 Java 开发人员,同时也在学习 C# 和 .Net。最近了解到Java中有上限和下限通配符。

<? extends AbstractClass> // upper bounded wildcard
<? super ConcreteClass>   // lower bounded wildcard

我尝试在谷歌上搜索答案,但我只阅读了关于变异性的信息,这让我更加困惑。

在 C# 中可以做这样的事情吗?:

public static void addCat(List<? super Cat> list) {
    list.add(new Cat());
}

// ...

interface Pet {}
class Cat implements Pet {}
class Dog implements Pet {}

// ...

public static void main(String[] args) {
    List<Pet> pets = new ArrayList<>();
    pets.add(new Dog());
    addCat(pets);
}

【问题讨论】:

  • 在 C# 中我们可以做到。由于DogCat 类实现了相同的接口,并且您正在创建Pet 的接口(IPet 是接口的专有名称)列表,它将添加实现相同接口的两个类的实例。
  • 您在编写代码时已经知道super CatPet,不是吗?我看不出写List&lt;super Cat&gt; 比写List&lt;Pet&gt; 有什么好处
  • @ThomasWeller 抱歉,我在学习示例中忘记了,Cat 实现了两个接口。我想告诉调用者我想要一个可以包含CatList,但我不会将列表限制为 包含Cat 对象。

标签: java c#


【解决方案1】:

C# 还支持与 Java 中的“上/下”通用界限密切相关的方差(协变和逆变)。

但是,不可能使某些类变体。事实上,只有泛型接口和泛型委托类型支持变体。

为了将某个接口标记为协变(即能够使用比原始类型更多的派生类型),您需要在其泛型类型参数旁边使用out关键字,如如示例所示:

interface IPetHouse<out T> where T : IPet
{
    T Pet { get; }
};

class CatHouse : IPetHouse<Cat>
{
    public Cat Pet => new Cat();
}

class DogHouse : IPetHouse<Dog>
{
    public Dog Pet => new Dog();
}

// 'out' keyword gives possibility to treat CatHouse and DogHouse as IPetHouse<IPet> since IPet is less derived type
var petHouses = new IPetHouse<IPet>[] {
    new CatHouse(), 
    new DogHouse()
};

// Types are preserved, which you can check easily 
petHouses.Select(ph => ph.Pet.GetType().Name); //outputs: Cat and Dog 

另一方面,要将接口标记为逆变(即能够使用比最初指定的更通用(派生较少)的类型),您需要在其旁边使用in关键字泛型类型参数,如示例所示:

interface IPetHouse<in T> where T : IPet
{
    void AddPet(T pet);
};

class PetHouse : IPetHouse<IPet>
{
    public void AddPet(IPet pet)
    {
    }
}

class CatHouse : IPetHouse<Cat>
{
    public void AddPet(Cat pet)
    {
    }
}

// 'in' keyword gives possibility to treat PetHouse as a CatHouse, since Cat is more derived type
IPetHouse<IPet> petHouse = new PetHouse();
IPetHouse<Cat> catHouse = petHouse;
catHouse.AddPet(new Cat()); // requires Cat to be passed

更多信息可以在官方MSDN上找到page

【讨论】:

  • 很好的解释。但是在您的逆变示例中,最后一行应该是 catHouse.AddPet(new Cat());
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-29
  • 1970-01-01
  • 1970-01-01
  • 2010-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多