首页 > 解决方案 > 当方法在基类中定义时,如何将方法的参数限制为子类类型?

问题描述

假设我有

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:根据链接的问题/彼得的评论,这是如何实施的

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) { }
}

它似乎确实有效,但感觉就像是为了获得类型约束而增加了很多额外的东西,而且明显的自我引用对我来说感觉很奇怪。也许这是最好的。我将看看是否可以找到有关此模式的更多信息。

标签: c#inheritance

解决方案


涉及两个参数和两个类型参数。您需要确保它们都是水果并且它们是同一类型。

public bool CompareFruit<T1, T2>(T1 fruit1, T2 fruit2) where T1 : Fruit, T2
                                                       where T2 : Fruit
{
    return fruit1.Size == fruit2.Size;
}

推荐阅读