向下转换父类属性以调用特定于孩子的方法的正确方法是什么?

时间:2019-05-01 20:22:28

标签: c# oop abstract-class

我已经遇到过几次这个问题,而我找不到答案的事实使我觉得我在根本上做些奇怪的事情,但是这里有:

我有一个抽象类,其中包含一个接口(或抽象类)属性,该属性定义任何子级将需要的所有常用方法:

interface IFoo
{
    ...
}

abstract class Parent
{
    IFoo Foo { get; set; }
}

然后我有一个实现该抽象类的子类,并在其构造函数中将该接口属性设置为其自己的实现:

class Child : Parent
{
    Child()
    {
       Foo = new ChildFoo();
    }
}

class ChildFoo : IFoo
{
    SomeMethod()
    {
    }
}

问题在于,每当我需要在Child中调用SomeMethod()时,都需要先将Foo转换为ChildFoo。我是否应该在Child中添加仅将Foo返回为ChildFoo的getter属性?还是我在根本上做错了什么?

编辑:

我为编辑和不接受答案(实际上可能仍然有效)道歉,但是我觉得我应该更加明确,因为我仍然迷失了方向。

Parent和Child实际上是OData控制器,IFoo是定义基本CRUD方法的服务层接口。

有许多子OData控制器,它们都包含IFoo定义的CRUD方法的端点。但是,某些子级也具有自定义函数端点,这些端点调用IFoo中未定义的特定于实体的方法。

我希望通过使用IFoo属性使所有通用子终结点在父控制器中调用通用方法来避免大量冗余的控制器代码。问题在于,如果不将IFoo转换为ChildFoo(),则无法在Child控制器中调用特定于实体的方法。

我开始认为我应该完全删除Parent控制器,并添加一个包含带有IFoo参数的方法的帮助器类。

很抱歉,如果我只是重复自己。.

谢谢

2 个答案:

答案 0 :(得分:2)

您在根本上做错了什么。您在构造函数中将Foo设置为ChildFoo,但是公开了一个属性获取器,您可以在其中让任何人将其设置为 any { {1}}实例。

您要么需要确保没有任何人可以将该属性设置为构造函数将其设置为只读的属性(通过将其设置为只读),然后可以放心地确保它始终是{ {1}}(在这种情况下,您应该将其简单地存储在该类型的字段中,并让readonly属性返回它,而不是在每次使用它时都将其强制转换)。或者,如果需要在外部设置它,则IFoo显然需要该方法,因为您需要任何ChildFoo实例才能执行该操作。

答案 1 :(得分:1)

一个基本问题是,如果您有一个IFoo并将其强制转换为实现IFoo的特定类,例如ChildFoo

诸如IFoo之类的接口的重点是让其他代码处理该接口,而不是实现该接口的任何具体类型。如果其他地方的代码“知道” IFoo实际上是ChildFoo,则IFoo已经失去了存在的理由。

  • 如果ChildFoo是唯一实现IFoo的类,则您不需要IFoo。 (也许除了单元测试外,但是如果将接口强制转换为具体类型,那还是行不通的。)
  • 如果其他类实现了IFoo,那么您如何知道给定的IFooChildFoo而不是其他实现IFoo的其他类呢?
  • 即使ChildFoo是现在唯一实现IFoo的类,如果其他类稍后再实现IFoo怎么办?

当我们将接口强制转换为实现接口的对象时,我们会自行承担所有这些细节的跟踪,这是有风险的,并可能导致运行时错误。

但是我们也失去了接口的预期好处之一,那就是我们的代码仅取决于接口,而没有任何特定的实现。