gpt4 book ai didi

c# - 泛型方法可以使用逆变/协变类型吗?

转载 作者:太空狗 更新时间:2023-10-29 18:05:32 26 4
gpt4 key购买 nike

我正在编写一个通用方法以在 T4 模板的特殊任务中使用它。该方法应该允许我使用通用接口(interface)中的专用类型。我想到了以下签名:

interface IGreatInterface {
Object aMethodAlpha<U>(U parameter) where U : IAnInterface;
Object aMethodBeta(IAnInterface parameter)
}

public class AnInterestingClass : IAnInterface{}

当我尝试执行 IGreatInterface 时编译器为 aMethodBeta() 标记错误因为我已经让我的 T4 使用 IAnInterface 的子类型编写该方法(即我想像这样实现该方法:Object aMethodBeta(AnInterestingClass parameter))。

方法aMethodAlpha<U>()可以使用,但没有我想要的那么干净,因为我的 T4 必须生成一些额外的代码。我(也许是错误的)建议该方法的实现,必须由 T4 完成,可以是
Object aMethodAlpha<AnInterestingClass>(AnInterestingClass parameter) .

我认为泛型方法不支持逆变类型,但我不确定;我想这是编译器阻止编码器使用具有未在通用类型中定义的方法的特定类型的方式...

  1. 泛型方法在实现时是否必须使用确切的类型?
  2. 有什么技巧可以改变这种行为吗?

最佳答案

这个问题比较迷惑。让我看看是否可以澄清。

When I try to implement IGreatInterface the compiler flags an error for aMethodBeta() because I've made that method using a subtype of IAnInterface I want to implement that method like this: Object aMethodBeta(AnInterestingClass parameter).

那是不合法的。稍微简化一下:

class Food {}
class Fruit : Food {}
class Meat : Food {}
interface IEater
{
void Eat(Food food);
}
class Vegetarian : IEater
{
public void Eat(Fruit fruit);
}

Vegetarian不履行IEater的契约(Contract).你应该能够通过任何食物来吃,但是Vegetarian只接受水果。 C# 不支持虚方法形式参数协变,因为那不是类型安全的。

现在,你可能会说,这个怎么样:

interface IFruitEater
{
void Eat(Fruit fruit);
}
class Omnivore : IFruitEater
{
public void Eat(Food food);
}

现在我们有了类型安全; Omnivore可以用作 IFruitEater因为 Omnivore可以吃水果,以及任何其他食物。

不幸的是,C# 不支持虚方法形式参数类型逆变,尽管这样做在理论上是类型安全的。很少有语言支持这一点。

同样,C# 也不支持虚方法返回类型变化

我不确定这是否真的回答了您的问题。你能澄清一下这个问题吗?

更新:

关于:

interface IEater
{
void Eat<T>(T t) where T : Food;
}
class Vegetarian : IEater
{
// I only want to eat fruit!
public void Eat<Fruit>(Fruit food) { }
}

不,这也不合法。 IEater的契约(Contract)是你将提供一个方法 Eat<T>可以采取任何 T那是一个Food .你不能部分执行契约(Contract),你不能这样做:

interface IAdder
{
int Add(int x, int y);
}
class Adder : IAdder
{
// I only know how to add two!
public int Add(2, int y){ ... }
}

但是,您可以这样做:

interface IEater<T> where T : Food
{
void Eat(T t);
}
class Vegetarian : IEater<Fruit>
{
public void Eat(Fruit fruit) { }
}

这是完全合法的。但是,您不能这样做:

interface IEater<T> where T : Food
{
void Eat(T t);
}
class Omnivore : IEater<Fruit>
{
public void Eat(Food food) { }
}

同样,C#不支持虚方法形参逆变或协变。

请注意,C# 确实支持参数多态性协变,但已知这样做是类型安全的。例如,这是合法的:

IEnumerable<Fruit> fruit = whatever;
IEnumerable<Food> food = fruit;

水果序列可以用作食物序列。或者,

IComparable<Fruit> fruitComparer = whatever;
IComparable<Apples> appleComparer = fruitComparer;

如果你有东西可以比较任何两个水果,那么它就可以比较任何两个苹果。

但是,这种协变和逆变只有在满足以下所有条件时才合法:(1) 变型可证明是类型安全的,(2) 类型的作者添加了变型注释,表明所需的协变和逆变差异,(3) 涉及的可变类型参数都是引用类型,(4) 泛型类型是委托(delegate)或接口(interface)。

关于c# - 泛型方法可以使用逆变/协变类型吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8099833/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com