C# 相互依赖的泛型类?
本文底部是一个解决方案的示例,尽管该示例显然无效,因为它在继承时使用了BaseNode和BaseEdge,但没有提供类型 我试图创建一个抽象图类,其中node类和edge类都必须是抽象的。每个类的单独实现将添加方法和属性,以及从基类实现抽象方法 我有一个现有的解决方案,它只对所有内容使用基本类型,但是我很快发现自己在铸造方面一团糟 只有graph类必须公开,尽管其他类可以公开,因此包含嵌套在graph类中的节点和边类的解决方案是可以接受的 是否有任何方法可以将其结构化,以便所有属性都是正确的类型,而不会在系统中任何地方进行昂贵的强制转换?更重要的是,实现类不必到处强制转换,但在这种情况下,性能肯定是一个问题(实际上是),所以我宁愿避免完全强制转换C# 相互依赖的泛型类?,c#,.net,generics,polymorphism,graph-theory,C#,.net,Generics,Polymorphism,Graph Theory,本文底部是一个解决方案的示例,尽管该示例显然无效,因为它在继承时使用了BaseNode和BaseEdge,但没有提供类型 我试图创建一个抽象图类,其中node类和edge类都必须是抽象的。每个类的单独实现将添加方法和属性,以及从基类实现抽象方法 我有一个现有的解决方案,它只对所有内容使用基本类型,但是我很快发现自己在铸造方面一团糟 只有graph类必须公开,尽管其他类可以公开,因此包含嵌套在graph类中的节点和边类的解决方案是可以接受的 是否有任何方法可以将其结构化,以便所有属性都是正确的类型
abstract class Graph<TNode, TEdge>
where TNode : BaseNode<TEdge>
where TEdge : BaseEdge<TNode>
{
TNode root;
List<TNode> nodes;
List<TEdge> edges;
public abstract float process();
}
abstract class BaseNode<TEdge>
// THIS HERE IS THE PROBLEM
where TEdge : BaseEdge
{
List<TEdge> inputs;
public List<TEdge> Inputs
{
get
{
return inputs;
}
}
public abstract float process();
}
abstract class BaseEdge<TNode>
// THIS HERE IS THE PROBLEM
where TNode : BaseNode
{
TNode from;
TNode to;
public TNode To
{
get
{
return to;
}
}
public TNode From
{
get
{
return from;
}
}
public abstract float process();
}
更新 另一个答案是提供某种类型的安全性
public interface IGraph<TNode, TEdge>
where TNode : INode
where TEdge : IEdge
{
TNode Root { get; set }
List<TNode> Nodes { get; set; }
List<TEdge> Edges { get; set; }
}
public interface INode
{
List<IEdge> Edges { get; set; }
}
public interface INode<TEdge> where TEdge : IEdge
{
List<TEdge> Edges { get; set; }
}
public interface IEdge
{
INode To { get; set; }
INode From { get; set; }
}
public interface IEdge<TNode> where TNode : INode
{
TNode To { get; set; }
TNode From { get; set; }
}
public class MyGraph : IGraph<MyNode, MyEdge>
{
public MyGraph(MyNode root)
{
Root = root;
}
public MyNode Root { get; set; }
public List<MyNode> Nodes { get; set; }
public List<MyEdge> Edges { get; set; }
}
public class MyNode : INode<MyEdge>, INode
{
public List<MyEdge> Edges { get; set; }
List<IEdge> INode.Edges
{
get { return this.Edges; }
set { this.Edges = value; }
}
}
public class MyEdge : IEdge<MyNode>, IEdge
{
public MyNode To { get; set; }
public MyNode From { get; set; }
INode IEdge.To
{
get { return this.To; }
set { this.To = value; }
}
INode IEdge.From
{
get { return this.From; }
set { this.From = value; }
}
}
在您为@marceln提供的示例中,Graph
类不是泛型的。因此,你必须进行各种类型的铸造。但对于通用版本:
public abstract Graph<TNode, TEdge>
where TNode : BaseNode<TEdge>
where TEdge : BaseEdge<TNode>
{
public TNode Root { get; set; }
public List<TNode> Nodes { get; set; }
public List<TEdge> Edges { get; set; }
}
public abstract BaseNode<TEdge> where TEdge : BaseEdge<BaseNode<TEdge>>
{
public List<TEdge> Edges { get; set; }
}
public abstract BaseEdge<TNode> where TNode : BaseNode<BaseEdge<TNode>>
{
public TNode To { get; set; }
public TNode From { get; set; }
}
public class MyNode : BaseNode<TEdge> where TEdge : BaseEdge<MyNode>
{
...
}
public class MyEdge : BaseEdge<TNode> where TNode : BaseNode<MyEdge>
{
...
}
public class MyGraph : Graph<MyNode, MyEdge>
{
...
}
public MyGraph<MyNode, MyEdge> g = new MyGraph<MyNode, MyEdge>();
List<MyEdge> edges = g.Nodes[0].Edges;
MyNode toNode = g.Edges[0].To;
公共抽象图
其中TNode:BaseNode
TEdge:BaseEdge在哪里
{
公共TNode根{get;set;}
公共列表节点{get;set;}
公共列表边{get;set;}
}
公共抽象BaseNode,其中TEdge:BaseEdge
{
公共列表边{get;set;}
}
公共抽象BaseEdge,其中TNode:BaseNode
{
{get;set;}的公共TNode
来自{get;set;}的公共TNode
}
公共类MyNode:BaseNode,其中TEdge:BaseEdge
{
...
}
公共类MyEdge:BaseEdge,其中TNode:BaseNode
{
...
}
公共类MyGraph:Graph
{
...
}
公共MyGraph g=新MyGraph();
列表边=g.Nodes[0]。边;
MyNode toNode=g.Edges[0]。到;
这允许从
图形
派生的任何类型都具有强类型的节点和边,这就是OP所要寻找的。如果您愿意放松对BaseEdge
和BaseNode
的约束,则可以执行以下示例中的操作
我已经介绍了接口INode
和IEdge
,这样任何使用它的人都不允许创建任何类型的BaseEdge
和BaseNode
的具体子类
public interface INode
{
}
public interface IEdge
{
}
public abstract class Graph<TNode, TEdge>
where TNode : BaseNode<TEdge>
where TEdge : BaseEdge<TNode>
{
public TNode Root { get; set; }
public List<TNode> Nodes { get; set; }
public List<TEdge> Edges { get; set; }
}
public abstract class BaseNode<TEdge> : INode where TEdge: IEdge
{
List<TEdge> inputs;
public List<TEdge> Inputs
{
get
{
return inputs;
}
}
public abstract float process();
}
public abstract class BaseEdge<TNode> : IEdge where TNode: INode
{
TNode from;
TNode to;
public TNode To
{
get
{
return to;
}
}
public TNode From
{
get
{
return from;
}
}
public abstract float process();
}
public class ConcreteNode : BaseNode<ConcreteEdge>
{
public override float process()
{
return 0;
}
}
public class ConcreteEdge : BaseEdge<ConcreteNode>
{
public override float process()
{
return 0;
}
}
public class ConcreteGraph : Graph<ConcreteNode, ConcreteEdge>
{
}
公共接口INode
{
}
公共接口边缘
{
}
公共抽象类图
其中TNode:BaseNode
TEdge:BaseEdge在哪里
{
公共TNode根{get;set;}
公共列表节点{get;set;}
公共列表边{get;set;}
}
公共抽象类BaseNode:INode,其中TEdge:IEdge
{
列出投入;
公开列表输入
{
得到
{
返回输入;
}
}
公共抽象浮动过程();
}
公共抽象类BaseEdge:IEdge,其中TNode:INode
{
TNode来自;
TNode to;
公共TNode To
{
得到
{
返回;
}
}
公共TNode来自
{
得到
{
返乡;
}
}
公共抽象浮动过程();
}
公共类节点:BaseNode
{
公共覆盖浮点进程()
{
返回0;
}
}
公共类ConcreteEdge:BaseEdge
{
公共覆盖浮点进程()
{
返回0;
}
}
公共类图:图
{
}
谢谢@marceln。你是说现有的解决方案吗?或者是一个实施的例子?任何对你来说更容易的。只要问题还存在,举个例子就可以了。对不起,如果我不理解@marceln,那么我不能完全确定你想要什么额外的信息。问题出现在包含的代码中,因为行其中的TEdge:BaseEdge
和其中的TNode:BaseNode
无效,因为BaseEdge和BaseNode是泛型类型,但不能以BaseNode
的形式使用,感谢标记@Sahuagin。我现在按照@marceln的要求添加了一个进一步的示例。BaseEdge
和BaseNode
的定义是什么样子的?@marceln Hehe,我现在正在VS中查看它,以确保它是正确的……最重要的是,它能够编译;):)我想如果它能起作用那就太好了。但是我不知道如何才能绕过这个BaseEdge,其中TNode:BaseNode
。此外,示例中缺少类
关键字。是的,这就是我一直使用@marceln的原因。我希望有一些我没有意识到的技巧,但看起来不太可能。你可能可以做类似的事情,但这需要反思来摆脱铸造…但是,铸造仍将在封面下进行。最后,必须有一个更简单的解决方案。谢谢,这可能是我能找到的最接近解决方案,尽管正如我在上面的评论中所说的,这并没有特别巧妙地处理BaseNode和BaseEdge也包含方法的事实,因为它们仍然需要在内部强制转换。我自己会继续做一段时间,但除非我能想出更好的解决方案,否则我会接受这个解决方案。呵呵,那很好。@fourpastmidnight如果BaseNode
和BaseEdge
需要在内部进行操作,那么为什么不在其他类中实现每个节点或每个边缘处理,并将它们设置为属性呢?所以,把所有依赖于节点/边缘的代码放在基类之外,否则你可能会得到处理每一种或大多数具体类型的巨大实现。是的,我想这可能是实际的方法。这是可以做到的,但这意味着一个巨大的挑战
Graph<TNode, TEdge> where TNode : BaseNode<TEdge>, TEdge : BaseEdge<TNode>
public abstract Graph<TNode, TEdge>
where TNode : BaseNode<TEdge>
where TEdge : BaseEdge<TNode>
{
public TNode Root { get; set; }
public List<TNode> Nodes { get; set; }
public List<TEdge> Edges { get; set; }
}
public abstract BaseNode<TEdge> where TEdge : BaseEdge<BaseNode<TEdge>>
{
public List<TEdge> Edges { get; set; }
}
public abstract BaseEdge<TNode> where TNode : BaseNode<BaseEdge<TNode>>
{
public TNode To { get; set; }
public TNode From { get; set; }
}
public class MyNode : BaseNode<TEdge> where TEdge : BaseEdge<MyNode>
{
...
}
public class MyEdge : BaseEdge<TNode> where TNode : BaseNode<MyEdge>
{
...
}
public class MyGraph : Graph<MyNode, MyEdge>
{
...
}
public MyGraph<MyNode, MyEdge> g = new MyGraph<MyNode, MyEdge>();
List<MyEdge> edges = g.Nodes[0].Edges;
MyNode toNode = g.Edges[0].To;
public interface INode
{
}
public interface IEdge
{
}
public abstract class Graph<TNode, TEdge>
where TNode : BaseNode<TEdge>
where TEdge : BaseEdge<TNode>
{
public TNode Root { get; set; }
public List<TNode> Nodes { get; set; }
public List<TEdge> Edges { get; set; }
}
public abstract class BaseNode<TEdge> : INode where TEdge: IEdge
{
List<TEdge> inputs;
public List<TEdge> Inputs
{
get
{
return inputs;
}
}
public abstract float process();
}
public abstract class BaseEdge<TNode> : IEdge where TNode: INode
{
TNode from;
TNode to;
public TNode To
{
get
{
return to;
}
}
public TNode From
{
get
{
return from;
}
}
public abstract float process();
}
public class ConcreteNode : BaseNode<ConcreteEdge>
{
public override float process()
{
return 0;
}
}
public class ConcreteEdge : BaseEdge<ConcreteNode>
{
public override float process()
{
return 0;
}
}
public class ConcreteGraph : Graph<ConcreteNode, ConcreteEdge>
{
}