【发布时间】:2021-07-21 18:15:31
【问题描述】:
假设我有
class Program
{
static void Main(string[] args)
{
Apple myApple = new Apple(5);
Orange myOrange = new Orange(5);
bool isSame = myApple.Compare(myOrange);
}
}
class Fruit
{
private readonly int _Size;
public Fruit(int size)
{
_Size = size;
}
public bool Compare<T>(T otherFruit) where T : Fruit
{
if (this._Size == otherFruit._Size) return true;
return false;
}
}
class Apple : Fruit
{
public Apple(int size) : base(size) { }
}
class Orange : Fruit
{
public Orange(int size) : base(size) { }
}
而且我不想将苹果与橙子进行比较。我知道我可以
public bool Compare<T>(T otherFruit) where T : Fruit
{
if (this.GetType() != otherFruit.GetType()) return false;
if (this._Size == otherFruit._Size) return true;
return false;
}
但感觉我应该能够通过类型约束来做到这一点。
我可以做到这一点(即使它很丑),而且它看起来可以工作,但没有达到我的预期
public bool Compare<T>(T otherFruit) where T : Fruit
{
return Compare(otherFruit, this);
}
public static bool Compare<T>(T fruit1, T fruit2) where T : Fruit
{
if (fruit1._Size == fruit2._Size) return true;
return false;
}
我怎样才能使我在基类中定义的比较方法在子类中运行时只允许与子类匹配的参数类型? (因此理想情况下,在编译时您只能将 Apples 与 Apples 以及 Oranges 与 Oranges 进行比较)?
有趣的是,如果我用扩展方法替换实例比较方法,它会做我想要/期望的(我得到编译时检查,我只是比较苹果和苹果)
static class FruitComparer
{
public static bool Compare<T>(this T currentFruit, T otherFruit) where T : Fruit
{
return Fruit.Compare(currentFruit, otherFruit);
}
}
但同样,似乎应该有一种更简单的方法来做到这一点......也许我错过了一些非常明显的东西?
编辑:这确实有效(你会得到编译时检查,只有 Apples 可以与 Apples 进行比较),但前提是直接调用
public static bool Compare<T, U>(T fruit1, U fruit2) where T:Fruit,U where U:Fruit
{
if (fruit1._Size == fruit2._Size) return true;
return false;
}
奇怪的是,如果您从我的实例比较方法中调用该静态方法,您不会得到编译时检查 - 它可以让您将 Apples 与 Oranges 进行比较。
EDIT2:这是根据链接的问题/彼得的 cmets 实现的方法
class Fruit<X>
{
private readonly int _Size;
public Fruit(int size)
{
_Size = size;
}
public bool Compare<T>(Fruit<T> otherFruit) where T: Fruit<X>
{
return true;
}
}
class Apple : Fruit<Apple>
{
public Apple(int size) : base(size) { }
}
class Orange : Fruit<Orange>
{
public Orange(int size) : base(size) { }
}
而且它似乎确实有效,但感觉就像是为了获得类型约束而添加了很多额外的东西,而且明显的自我引用对我来说感觉很奇怪。也许这是最好的。我将看看是否可以找到有关此模式的更多信息。
【问题讨论】:
-
你应该使基类泛型,其中类型参数是派生类型的类型。例如。
class Apple : Fruit<Apple>。如果没有具体说明它所期望的哪个派生类型,则不允许代码使用基类,确保您只比较苹果和苹果、橙子和橙子,而不是苹果和橙子。查看副本。 -
谁结束了这个问题 - 虽然这个问题似乎在标题中提出了同样的问题,但它实际上有些不同并且可以说更复杂。当然给出的答案更复杂,我在这里提出的扩展方法可能性。
-
问题的上下文略有不同,但基本相同,答案相同。如果你不能限制调用者在处理基类时知道他们在处理什么水果,那么就没有办法保证兼容的比较。如果你可以约束调用者,那么通过将泛型类型参数从方法移动到类来实现你想要的,就像在副本中一样。
-
@PeterDuniho 这种模式——通用基类的东西——很有趣。但是,我没有找到任何参考资料 1) 证明答案是最正确的(即“我如何正确...”)或支持您的假设“您应该”。当然,看起来我可以让它做我所追求的,但它似乎和我探索的其他选择一样(不必要地)复杂。此外,静态比较方法可以做我所追求的这一事实似乎暗示实例方法中缺少某些东西。
-
它被称为Curiously Recurring Template Pattern,它是目前在C#中强制执行的唯一方法,因为没有
where T : this约束
标签: c# inheritance