C# 具有强类型返回类型的抽象方法

C# 具有强类型返回类型的抽象方法,c#,generics,inheritance,overriding,abstract-class,C#,Generics,Inheritance,Overriding,Abstract Class,考虑以下类别: public abstract class Animal { public abstract Animal GiveBirth(); } public class Monkey : Animal { public override Animal GiveBirth() { return new Monkey(); } } public class Snake : Animal { public override Anim

考虑以下类别:

public abstract class Animal
{
    public abstract Animal GiveBirth();
}

public class Monkey : Animal
{
    public override Animal GiveBirth()
    {
        return new Monkey();
    }
}

public class Snake : Animal
{
    public override Animal GiveBirth()
    {
        return new Snake();
    }
}

//That one doesnt makes sense.
public class WeirdHuman: Animal
{
    public override Animal GiveBirth()
    {
        return new Monkey();
    }
}
我正在寻找一种方法来强制重写的
GiveBirth
方法的返回类型,以便它总是返回实际的类类型,这样就没有
WeirdHuman
可以生成
Monkey

我觉得答案是关于泛型类型的,但我不知道如何才能做到这一点

预期结果的示例:

public abstract class Animal
{
    public abstract /*here a way to specify concrete type*/ GiveBirth();
}

public class Monkey : Animal
{
    public override Monkey GiveBirth() //Must returns an actual Monkey
    {
        return new Monkey();
    }
}

如果解释清楚,“绝对不可能”可能是一个答案。

这是共变量返回,C#不支持。我每天都为此感到惋惜。为了避免这种情况,您最好使用泛型返回类型,并在泛型类型上指定where条件,但这也会导致您遇到其他问题,并满足泛型参数要求

public abstract class Animal<TBirthType> where TBirthType : Animal<TBirthType>
{
    public abstract TBirthType GiveBirth();
}

public class Monkey<TBirthType> : Animal<TBirthType> where TBirthType : Monkey<TBirthType>
{
    public override TBirthType GiveBirth()
    {
        return new Monkey<Monkey>();
    }
}
公共抽象类Animal,其中TBirthType:Animal
{
公共摘要TBirthType GIVEBORTH();
}
公共类猴子:动物类型:猴子
{
公共覆盖TBirthType GIVEBORTH()
{
返回新猴子();
}
}
或者,如果不需要任何进一步的继承,可以关闭泛型

public class Monkey : Animal<Monkey>
{
    public override Monkey GiveBirth()
    {
        return new Monkey();
    }
}
公共类猴子:动物
{
公共优先权
{
返回新猴子();
}
}

请注意,仅协方差还不足以确保不会形成行为不端的派生类型,但它允许将返回的类型指定为正在使用的类型。但是仍然没有办法从抽象类中锁定它。您可能可以通过在运行时检查类型的基本级别实现的方法的反射来管理运行时检查,但这也可能非常混乱。

您可以这样做,这迫使
Animal
的实现者实现
Animal GiveBirth()
方法,该方法返回与type参数相同的类型,而type参数本身被约束为一种动物

这不是你想要的,但你可以看到:

public abstract class Animal<T> where T: Animal<T>
{
    public abstract Animal<T> GiveBirth();
}

public class Monkey: Animal<Monkey>
{
    public override Animal<Monkey> GiveBirth()
    {
        return new Monkey();
    }
}

public class Snake: Animal<Snake>
{
    public override Animal<Snake> GiveBirth()
    {
        return new Snake();
    }
}

public class WeirdHuman: Animal<WeirdHuman>
{
    public override Animal<WeirdHuman> GiveBirth()
    {
        return new Monkey(); // Won't compile of course.
    }
}
公共抽象类Animal,其中T:Animal
{
公共抽象动物分娩();
}
公营猴子:动物
{
公共优先于动物分娩()
{
返回新猴子();
}
}
公营蛇:动物
{
公共优先于动物分娩()
{
返回新的Snake();
}
}
公共课怪人:动物
{
公共优先于动物分娩()
{
return new Monkey();//当然不会编译。
}
}
如果您注释掉
public override Animal GiveBirth()
方法,您将看到编译器抱怨并说:

错误1“ConsoleApplication1.Monkey”未实现继承的抽象成员“ConsoleApplication1.Animal.GiveBirth()

不幸的是,您必须使用
somekindofamal:Animal
语法来声明类,但这可能适用于您

()

唉,这不太管用,因为它允许您这样做:

public class Monkey: Animal<WeirdHuman>
{
    public override Animal<WeirdHuman> GiveBirth()
    {
        return new WeirdHuman();
    }
}
公共类猴子:动物
{
公共优先于动物分娩()
{
返回新的怪人();
}
}
也就是说,它将type参数约束为一种动物,还将
GiveBirth()
的返回类型约束为与type参数相同;但这就是它的全部功能。在某些情况下,这就足够了,但可能不是为了你的目的


尽管如此,也许这种方法值得了解。

据我所知,没有一种干净的方法可以完全在单个类层次结构中支持这种方法。使用重复出现的泛型类型参数,例如

public class Animal<T> where T : Animal<T> { }
公共类动物,其中T:Animal{}
如果控制整个层次结构,则可能是可以接受的,因此可以排除以下类

public class WierdHuman<Monkey> { }
公共类WierdHuman{}
您真正想要的是类似于Haskell的TypeClass的东西,在这里您可以抽象类本身的具体类型。在C#中,最接近的方法是定义一个代理对象来实现所需的功能,然后在任何需要的地方传递它

在您的案例中,这意味着为分娩创建一个接口,并为每种具体的动物类型实现它

需要此功能的方法需要为“typeclass实例”提供一个额外的参数。这些方法可以限制通用动物类型相同:

public interface ISpawn<T> where T : Animal
{
    public T GiveBirth();
}

public void Populate<T>(T parent, ISpawn<T> spawn) where T : Animal
{
}
显示公共界面,其中T:Animal
{
公共分娩();
}
公共空白填充(T父代,ISpawn卵),其中T:Animal
{
}

我就是这么想的。我找不到任何方法来指定泛型类型必须实现实际的类类型。比如
where T:this
或者其他什么…支持它的语言是什么?Java支持它。Net不支持它,因为CLR是根本问题。希望将来的版本会增加支持,但据我所知,这需要进行实质性的更改才能正常工作。@Johnny5-刚刚更新了我的答案,添加了一个关闭通用版本的版本。如果您只需要一级继承,这可能很有用。返回类型协方差是不够的,因为无法强制执行从
GiveBirth
返回的具体类型与封闭类类型匹配。那么,如果有人制造了
Monkey:Animal
,并制造了真正的混乱婴儿,会发生什么情况?@Servy:)嗯,
GiveBirth()
方法仍然被限制为只返回一个
Monkey
,因此这满足了“强制重写的GiveBirth方法的返回类型的方法,以便它总是返回实际的类类型”(从OP)。如果你愿意,你可以说猴子是怪人!但它不必返回实现接口的类的类型,只返回实现接口的类选择的任何类型。@Servy:Yes-true;类型参数被约束为某种类型