【问题标题】:Restructuring Suggestions to remove lots of generic constraints重组建议以消除大量通用约束
【发布时间】:2011-01-31 20:27:05
【问题描述】:

我正在尝试找出是否有更好的方法来构建一些代码。尽管它目前有效,但由于泛型约束的复杂性和疯狂的性质,它总是让我感到困惑。我很想知道是否有人对更简洁的解决方案有想法。

我已经包含了一个类图,以使事情变得更容易一些。

这一切都在一个库中进行,我想尽量保持我所有的类型安全。该库有 3 层,其复杂性不断增加。我稍后会解释。

我正在使用泛型来使所有类型都工作。例如,Route 实际上是 List<T>,其中 T 是访问。现在因为我有 3 层,我希望能够从 Route 本身访问这些访问(以及它们对应的节点)的属性(并使其更易于使用)。所以这实际上是一个Route<Visit<Node>>。一旦你将它添加到需要强类型 Solution<Route<Visit<Node>>> 的解决方案中,事情就会变得复杂。

这会导致一些不雅的代码:

public abstract class Solution<TSolution, TRoute, TVisit, TNode, TResource>
   where TSolution : Solution<TSolution, TRoute, TVisit, TNode, TResource>, new()
   where TRoute : Route<TRoute, TVisit, TNode, TResource>, new()
   where TVisit : Visit<TVisit, TNode>, new()
   where TNode : Element<TNode>
   where TResource : Resource<TResource>

这一切都很好,但我必须在每个类/级别定义这些约束。在每个复杂级别,我都会创建一些简单的可消费类,如下所示,基本上隐藏了使其无法消费的通用约束。

Level1.Solution : Common.Solution<Solution, Route, Visit, Node, Resource>

它们还根据question 的建议进行了递归,以允许我扩展类。例如,Level2.Solution 需要能够将 Level2.Route 指定为约束之一,通常如果没有递归,这将不起作用(co/contra 方差和泛型)。

总而言之,它有效,但至少可以说有点令人生畏。任何人都知道如何很好地重新工作?

【问题讨论】:

  • 那个类图是用什么做的!?抱歉没有用的评论:我不得不问,它看起来很棒;)我发誓我看到了渐变等。如果是手工的话,我会整天捂脸。
  • 你真的需要泛型吗?例如,为什么在 Visit 中有 Visit 而不是硬编码类型节点属性?
  • @Steve:如果我没有泛型,那么当我不得不引入大量演员表时。例如,将 Level2.Visit 和 Level1.Visit 添加到 Route 之间没有区别。而我需要确保它们都是相同的类型,并且我可以访问它们的属性。如果不使用泛型,我将不得不一直在投射。
  • @Ian,我不确定是否理解。您已经定义了 Visit,例如可以是 Visit。你还有其他适合这个课程的课程吗?
  • 不是一个真正的答案,但我得出的结论是,一旦仿制药开始反击,就没有任何帮助。将它们降低到您严格需要的最低限度。那甚至可能根本没有。当然,集合应该是通用的——但我很想将这部分归为少数非通用接口。

标签: c# generics refactoring


【解决方案1】:

路由实际上是一个列表

如果您prefer composition over inheritance,我认为您的代码将大大简化。如果一个路线有一个列表,它会变得更简单,更容易管理。

【讨论】:

    【解决方案2】:

    我认为这里的问题是您试图将它们全部组合在一个地方。例如,您不必告诉解决方案有关 Node 及其合同的任何信息,但在您的情况下,您必须这样做。尝试使用接口而不是通用约束 - 您仍然可以从资源和节点组合的不同路由创建解决方案,但最终您只需要指定具体的解决方案:

    interface INode {}
    class Node: INode {}
    
    interface IVisit
    class Visit: IVisit
    {
        Visit(INode node) {}
    }
    
    interface ISolution {}
    class Solution: ISolution
    {
       Solution(IList<IRoute> routes)
       {
       }
    }
    

    【讨论】:

      【解决方案3】:

      我承认我可能遗漏了一些东西,但是看着这个问题和你链接的问题,我觉得这一切都过于复杂了。它看起来像是 syntaxophilia 的案例。当我遇到这样的事情时,通常需要坐下来以更简单的方式思考我正在建模的内容。

      据我了解,这些通用约束只是确保类型在 ResourceNodeVisitRouteSolution 类型参数之间兼容。一切都很好,如果非常复杂。唯一的“变量”是您的 TResourceTNode 类型。我的意思是,你可以:

      class Solution<TResource, TNode>
          where TNode : Element<TNode>
          where TResource : Resource<TResource>
      {
           //  Construct properties for the Visit and Route, as required
      }
      

      例如,您的示例表明 VSPSolution 始终具有 VSVPisit 和 VSPRoute。如果是这样的话,那么这里的组合解决方案就大大简化了事情。事实上,如果我更了解TNodeTResource 的用途,您可能也可以消除这些通用约束。

      真正的问题是Visit(或Route)对象是否必须存在于Solution 之外。在我看来它是一个非常严格的层次结构:Solution -> Route -> Visit,因此 Solution 包含 RouteRoute 包含 @ 是有​​意义的987654341@收藏。

      这样做更简单,而且更清楚发生了什么。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-18
        • 2011-01-24
        相关资源
        最近更新 更多