c# - 将 Type 用作 'Property' 是不好的做法吗?

标签 c# inheritance

目前我正在使用一些旧的 C# 代码,这些代码基本上使用派生类型的唯一目的是将类型用作“属性”,例如:

public abstract class Fruit
{
    public int Property { get; set; }
}

public class Apple : Fruit {}

public class Pear : Fruit {}

然后:

public void Foo(Fruit item)
{
    if(item is Apple)
    {
        // do something
        return;
    }
    if(item is Pear)
    {
        // do something
        return;
    }

    throw new ArgumentOutOfRangeException("item");
}

我会在 BaseClass 上包含一个枚举属性来指定“类型”:

public class Fruit
{
    public int Property { get; set; }

    public FruitType Type { get; set; }
}

public enum FruitType
{
    Apple,
    Pear
}

然后这样使用它:

public void Foo(Fruit item)
{
    switch(item.Type)
    {
        case FruitType.Apple:
            // do something
            break;
        case FruitType.Pear:
            // do something
            break;
        default:
            throw new ArgumentOutOfRangeException();
    }
}

我觉得前一种模式是对继承的滥用,但是在重写这段代码之前我应该​​考虑它有什么优点吗?

最佳答案

处理这种情况的标准“面向对象”方法是使 DoSomething 成为 Fruit 上的抽象方法。然后调用者只需调用 DoSomething,知道实现将做正确的事情。

这种方法的缺点是它将计算出用户可能想要的所有可能“东西”的责任推给了抽象类的作者。

可以通过使用“访问者模式”来减轻这种不利影响。访问者模式是一种标准方式,使第三方能够根据值的运行时类型有效地切换行为。您可以考虑对其进行研究。

您的第二种方法——使用标签区分类型——很常见并且非常有效。 Roslyn 广泛使用了这种技术。 OO纯粹主义者认为它有点臭,但幸运的是我不是OO纯粹主义者。

我喜欢的第二种技术的变体是:

public enum FruitKind { Apple, Orange }
public abstract class Fruit
{
  private Fruit(FruitKind kind)
  {
      this.Kind = kind;
  }
  public FruitKind Kind { get; protected set; }
  private class Apple : Fruit
  {
      public Apple() : base(FruitKind.Apple) {}
  }
  public static Fruit MakeApple() { return new Apple(); }
  // similarly for orange
}

现在,Fruit 用户可以唯一确定类型的方法是通过标记,因为无法访问 Apple 和 Orange。您知道没有第三方会制作自己的 Fruit,因为唯一的 Fruit 构造函数是私有(private)的。

关于c# - 将 Type 用作 'Property' 是不好的做法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14449699/

相关文章:

c# - SharePoint Online 身份验证失败

c# - RichTextBox 中 RTF 文件中损坏的超链接

c++ - QTimer::singleShot() 在给定对象的父类中查找指定的槽,而不是对象本身

Java - 扩展子类中的私有(private)方法

java - 在给定实例上重写compareTo方法的更简单方法

c# - WebApi 2 OAuth 外部登录访问 token 问题

c# - 在 JavaScript 和 C# Controller 之间传递数据 : Asp.Net MVC 4 Razor

c# - LINQ 使用 DTO 将 SQL Server 日期时间转换为字符串

c++ - 访问虚拟派生类的成员/方法

c++ - 调用重写的方法而不是直接的父亲