【问题标题】:How to implement Master/Detail classes using Generics and inheritance [duplicate]如何使用泛型和继承实现主/细节类[重复]
【发布时间】:2017-03-28 18:39:57
【问题描述】:

我正在使用泛型为数据模型编写基类。基类应支持: 带有 DetailKey 的 DetailClass(任何类型) MasterClass 与 MasterKey(任何类型)并持有 List<DetailClass>

每当我的 DM 中有主/从关系时,我想从这 2 个类继承。

这是基类的简化代码:

  class Master<TMKey, TDKey> {
    public readonly TMKey MKey;
    public readonly List<Detail<TMKey, TDKey>> Details;

    public Master(TMKey mKey) {
      MKey = mKey;
      Details = new List<Detail<TMKey, TDKey>>();
    }
  }

  class Detail<TMKey, TDKey> {
    public readonly TDKey DKey;
    public readonly Master<TMKey, TDKey> Master;

    public Detail(TDKey dKey, Master<TMKey, TDKey> master) {
      DKey = dKey;
      Master = master;
    }
  }

当我尝试从这些类继承时遇到了编译器问题:

  class Sub: Detail<int, DateTime> {
    public DateTime Date { get { return DKey; } }
    public string S;
    public Main main { get { return (Main)Master; } }

    public Sub(DateTime date, string s, Main main) : base(date, main) {
      S = s;
    }
  }

  class Main: Master<int, DateTime> {
    public int MainId { get { return MKey; } }
    public string M;
    public List<Sub> SubDetails { get { return (List<Sub>)Details; } } //compiler error

    public Main(int mKey, string m) : base(mKey) {
      M = m;
    }
  }

编译器错误:

Cannot convert type 'System.Collections.Generic.List&lt;FlatFileStore.Detail&lt;int, System.DateTime&gt;&gt;' to 'System.Collections.Generic.List&lt;FlatFileStore.Sub&gt;'

编译器似乎没有意识到:

Sub: Detail&lt;int, DateTime&gt;

有什么建议可以解决这个编译器限制吗?

如何更改 DM 类以避免任何编译器问题并实现高性能(即没有集合的副本)?

如果有工作示例代码将不胜感激。

Edit1: 无法使用 .ToList() 解决方案(请参阅下面的答案)。可能有数千个细节,.ToList() 可能会被调用数千次,每次都会创建一个包含数千个项目的新列表。

Edit2:原来的问题似乎是“Casting List - covariance/contravariance problem”的副本,所以我重写了它以更好地解释。另一个问题专门询问如何制作 List 的副本,因此该问题中的所有答案都回答了如何制作这样的副本。我现在的问题是如何设计类以避免编译器问题,而不使用复制带来的巨大性能问题。还有其他可能的解决方案,例如使用IReadOnlyList&lt;T&gt;,在该问题的答案中根本没有提到。但可能还有其他可能性,比如告诉 Master 类将哪个 Type 用于它创建的集合。或者另一种设计可能是可能的。或者...

【问题讨论】:

  • 做自己想做的事既不可能也不安全。基类属性类型允许将Detail&lt;int, DateTime&gt;any 实例添加到列表中,因此您不能保证列表仅包含Sub 值。如果你想要一个简单的演员表工作,你需要两件事:1) 派生类必须是创建列表的那个,2) 你需要使用IReadOnlyList&lt;T&gt; 而不是基类属性类型中的 List&lt;T&gt;,例如你可以分配IReadOnlyList&lt;Detail&lt;int, DateTime&gt;&gt; Details = new List&lt;Sub&gt;;
  • @PeterDuniho:您的评论帮助我更好地理解问题并调查可能的解决方案。我将尝试按照您的建议提出一些代码,除非您想以正确的答案提供代码。我希望您可以删除“标记为重复”。甚至您自己的评论也证明我的问题是不同的。正确设计 Master/Detail 类有很多挑战,我相信其他人会很高兴在这里找到该代码。另一个问题根本没有帮助。
  • “我重写了它以便更好地解释”——你应该小心那个编辑功能。编辑一个问题来改进它很好,但是一旦其他用户回答了您的问题,您就不能改变问题的基本性质(正如您在此处所做的那样)。发布一个新问题,在其中详细描述您迄今为止所学的内容(例如,试试我的建议),以及您仍在尝试解决的具体问题,这是一种更好的方法.我建议这样做。然后是其他用户可以解决的一个新的、可回答的问题。
  • 我同意不应从根本上改变问题。但我觉得“有什么建议可以解决这个编译器限制吗?”“需要如何更改 DM 类以避免任何编译器问题并实现高性能(即没有集合的副本) ?” 仍然要求他们同样的事情。请注意,Stackoverflow 明确要求我 “如果这个问题不同,请编辑它以解释它有何不同。” 我做了。我希望您现在可以删除 “由 Peter Duniho 标记为重复”。它可能会阻止其他人阅读此问题。
  • "which I did" -- 我承认它可以解释,但我的观点是您的编辑改变了问题,而不是解释了原始问题的不同之处。如果您愿意发布一个新问题,我很乐意为您提供答案,但从网站审核的角度来看,我认为上述问题应该保持关闭。在您的新问题中,请从头开始撰写(不是从这里复制/粘贴),提供我在my previous comment 中描述的详细信息

标签: c# generics master-detail


【解决方案1】:

这与协/逆变有关。解决此问题的一种方法是使用 linq 进行投射:

public List<Sub> SubDetails { get { return Details.Cast<Sub>().ToList(); } } 

此处显示其他解决方案和讨论:Casting List<T> - covariance/contravariance problem

【讨论】:

  • 感谢您的回答。但我不能使用 .ToList(),它每次都会创建一个全新的列表。想象一下,如果我有一个拥有数千个细节的 Master。 .ToList() 可以被调用数千次,每次都会创建一个包含数千个项目的列表。
  • 你的手似乎被束缚了。您可能必须考虑这种继承模型的替代方法。
  • 实际上我现在有一个可行的解决方案来解决我的问题,但是由于 Peter Duniho 将我的问题标记为重复,所以我无法在此处发布。我的解决方案与其他问题无关,所以我不能在那里发布我的答案。彼得希望我再次发布我的问题,那真的是重复的。似乎我无能为力。伤心。
  • 是的,我对您的问题的上述批评不以为然-有时问题需要发展。
猜你喜欢
  • 2011-08-17
  • 2011-08-19
  • 1970-01-01
  • 2020-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-07
  • 2020-03-02
相关资源
最近更新 更多