【问题标题】:inheritance, or should i use composition?继承,还是我应该使用组合?
【发布时间】:2018-06-01 03:49:25
【问题描述】:

假设我有一门课

public class Transfer 
{
    prop1
    prop2
    ....
    public List<SubTransfer> SubTransfers { get; set; }
}

我从一个连接到数据库的函数中得到的

现在我想要一个类,为 Transfer 和每个 SubTransfer 添加一个状态。

一个问题是我是否应该在这里使用继承?还是作曲?

我认为继承,所以我试图做这样的事情:

public ExtendedSubTransfer : SubTransfer
{
    public StatusEnum Status { get; set; }
}

public ExtendedTransfer : Transfer
{
    public StatusEnum Status { get; set;}
}

我的问题是我不知道如何在使用 ExtendedTransfer 时获得 ExtendedSubTransfer 的列表。

我知道我可以像这样使用关键字 new 覆盖 SubTransfers:

public new List<ExtendedSubTransfers> SubTransfers {get; set;}

它“合法”吗?或者您有其他建议吗?

感谢您的帮助!

【问题讨论】:

  • 简短的回答是'是的,它是合法的,但它取决于'。通过在此处介绍StatusEnum,您想达到什么目的?您将如何使用这些 ExtendedSubTransfersExtendedTransfer 类? (或什么)。

标签: c# .net inheritance polymorphism overriding


【解决方案1】:

它会编译,但它可能不会做你想做的事。请记住,List&lt;ExtendedSubTransfer&gt; 不会扩展 List&lt;SubTransfer&gt;。例如,如果您有任何使用基类的操作,您将得不到您想要的。为了演示,让我们假设基类有一个 ID,而您想要打印这些 ID。

public void PrintIds()
{
    ExtendedTransfer extendedTransfer = _database.GetExtendedTransfer(...);
    PrintSubTransferIds(extendedTransfer);
}

private PrintSubTransferIds(Transfer transfer)
{
    foreach(var subTransfer in transfer.SubTransfers)
    {
        Console.WriteLine(subTransfer.Id);
    }
}

除非您在从数据库加载项目时做了一些非常奇怪的事情,否则上述方法将不起作用。例如,如果您的加载代码看起来像...

public GetExtendedTransfer(...)
{
    ExtendedTransfer result = new ExtendedTransfer();
    List<ExtendedSubTransfer> subTransfers = _connection.QueryForSubTransfers(...);
    result.SubTransfers = subTransfers;
    return result;
}

然后就不行了。它不会打印任何子传输 ID,因为 transfer.SubTransfers 将是一个空列表。相反,当从数据库加载时,你必须做一些奇怪的事情......

public GetExtendedTransfer(...)
{
    ExtendedTransfer result = new ExtendedTransfer();
    List<ExtendedSubTransfer> subTransfers = _connection.QueryForSubTransfers(...);
    result.SubTransfers = subTransfers;
    Transfer subtypedResult = result;
    subtypedResult.SubTransfers = subTransfers.Cast<SubTransfer>();
    return result;
}

此外,以下情况将是编译时错误:

public void PrintIds()
{
    ExtendedTransfer extendedTransfer = _database.GetExtendedTransfer(...);
    PrintSubTransferIds(extendedTransfer.SubTransfers);
}

private PrintSubTransferIds(List<SubTransfer> subTransfers)
{
    foreach(var subTransfer in subTransfers)
    {
        Console.WriteLine(subTransfer.Id);
    }
}

这将无法编译,因为extendedTransfer.SubTransfers 的类型为List&lt;ExtendedSubTransfer&gt;,无法分配给List&lt;SubTransfer&gt;

更新:那你应该怎么做?

C#(4.X 及更高版本)允许在certain interfaces 上使用covariance,例如IReadOnlyList(C# 4.5 及更高版本)。这样你就可以...

public class Transfer 
{
    public virtual IReadOnlyList<SubTransfer> SubTransfers { get; private set; }
    public void SetSubTransfers(List<SubTransfer> subTransfers)
    {
        SubTransfers = subTransfers;
    }
}

public class ExtendedTransfer
{
    private List<ExtendedSubTransfer> _subTransfers;

    public override IReadOnlyList<SubTransfer> SubTransfers
    {
        get { return _subTransfers; }
    }

    public void SetSubTransfers(List<ExtendedSubTransfer> subTransfers)
    {
        _subTransfers = subTransfers;
    }
}

这将是我解决您的问题的最佳尝试。但是,您没有提到如何从数据库中获取实体。我认为EntityFramework 默认情况下不会对这种字段排列感到满意。

【讨论】:

  • 我可能没有像我想的那样提出我的问题。传输类是我从连接到数据库的 DAL 函数中获得的模型。传输类仅作为属性,它不连接到 dB 本身。我的问题主要是关于我如何在继承子传输的同时继承传输类
  • 对,但是某些代码会在某处新建一个 Transfer 类的实例,并根据数据库查询为其设置一些属性。如果您使用new,则该 Transfer 类将具有两个同名的属性。除非基于查询设置属性的代码是以我描述的方式编写的,否则它不会期待这种情况,只会设置两个字段之一。我不知道您如何将查询映射到实例,但如果您使用EntityFramework,那么它不会设置这两个字段。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-28
  • 1970-01-01
  • 1970-01-01
  • 2012-05-29
  • 1970-01-01
相关资源
最近更新 更多