在重写inheritance方法时避免使用显式类型转换

我有一个基本抽象类,也实现了一个特定的接口。

public interface IMovable where TEntity: class where T: struct { TEntity Move(IMover moverProvider); } public abstract class Animal : IMovable { ... public virtual Animal Move(IMover moverProvider) { // performs movement using provided mover } } 

然后我inheritance了一些类,其中一些必须覆盖基类的接口实现方法。

 public class Snake : Animal { ... public override Animal Move(IMover moverProvider) { // perform different movement } } 

我的接口方法在移动后返回相同的对象实例,因此我可以在return语句中使用链接或直接执行某些操作而不使用其他变量。

 // I don't want this if methods would be void typed var s = GetMySnake(); s.Move(provider); return s; // I don't want this either if at all possible return (Snake)GetMySnake().Move(provider); // I simply want this return GetMySnake().Move(provider); 

正如您在我的示例中所看到的,我在子类中的覆盖返回基类类型而不是运行类。 这可能需要我投出结果,我想避免。

如何定义我的接口和实现,以便我的覆盖将返回执行实例的实际类型?

 public Snake Move(IMover moverProvider) {} 

我建议将接口方法的返回类型更改为void并将链接行为移动到扩展方法,您可以在其中获取目标的实际类型,例如

 public interface IMovable where TEntity : class where T : struct { void MoveTo(IMover moverProvider); } public abstract class Animal : IMovable { public virtual void MoveTo(IMover mover) { } } public static class AnimalExtensions { public static TAnimal Move(this TAnimal animal, IMover mover) where TAnimal : Animal, IMovable { animal.MoveTo(mover); return animal; } } 

请注意,如果您需要更广泛地应用,可以使Move扩展更通用:

 public static TEntity Move(this TEntity entity, IMover mover) where TEntity : IMovable where T : struct { entity.MoveTo(mover); return entity; } 

您可以将Animal转换为接受具体类型作为类型参数的generics类型:

 public abstract class Animal : IMovable where T:Animal { public virtual T Move(IMover moverProvider) { ... } } public class Snake : Animal { public override Snake Move(IMover moverProvider) { ... } } 

怎么样:

 public virtual T Move(IMover moverProvider) where T : Animal { // performs movement using provided mover } 

有时您需要将当前类型作为方法返回值,并且必须在派生类中进行更改。 我会避免这种模式,因为它会导致奇怪的行为和不寻常的语法(如果你的模型变得复杂)但是试一试(主要因为非常小的层次结构看起来很简单):

 abstract class Animal : IMovable where TConcrete : Animal { public virtual T Move(IMover moverProvider) { return (T)this; // Cast to Animal to T isn't implicit } } sealed class Snake : Animal { public virtual Snake Move(IMover moverProvider) { return this; } } 

为什么这么糟糕? 当你需要声明一个Animal类型的generics变量时,你可以自己回答(实际上这会阻止你拥有一个带有该基类的变量)。

我要做的是明确这个要求 (使用类或扩展方法 – 在这种情况下使用其他名称):

 abstract class Animal : IMovable { // Please note that this implementation is explicit Animal IMovable.Move(IMover moverProvider) { return MoveThisAnimal(moverProvider); } protected virtual Animal MoveThisAnimal(IMover moverProvider) { // Peform moving return this; } } class Snake : Animal { public Snake Move(IMover moverProvider) { return (Snake)MoveThisAnimal(moverProvider); } protected override Animal MoveThisAnimal(IMover moverProvider) { // Peform custom snake moving return this; } } 

这很麻烦,但通过引入非通用的基本接口,扩展方法可以提供所需的结果。 如果您不关心向调用者公开“MoveFunc”,它也可以简化(删除第二个显式接口实现):

 public interface IMovable { IMovable MoveFunc(); } public interface IMovable : IMovable where TEntity : IMovable { new TEntity MoveFunc(); } public abstract class Animal : IMovable { protected virtual Animal MoveFunc() { // performs movement using provided mover Debug.WriteLine("Animal"); } Animal IMovable.MoveFunc() { return MoveFunc(); } IMovable IMovable.MoveFunc() { return ((IMovable)this).MoveFunc(); } } public class Snake : Animal { protected override Animal MoveFunc() { // performs movement using provided mover Debug.WriteLine("Snake"); } } public static class IMovableExtensions { public static TOut Move(this TOut entity) where TOut : IMovable { return (TOut)entity.MoveFunc(); } } ... Snake snake = new Snake(); Snake moved = snake.Move(); // "Snake" Animal animal = snake; animal.Move() // "Snake"