C# 相互依赖的泛型类?

C# 相互依赖的泛型类?,c#,.net,generics,polymorphism,graph-theory,C#,.net,Generics,Polymorphism,Graph Theory,本文底部是一个解决方案的示例,尽管该示例显然无效,因为它在继承时使用了BaseNode和BaseEdge,但没有提供类型 我试图创建一个抽象图类,其中node类和edge类都必须是抽象的。每个类的单独实现将添加方法和属性,以及从基类实现抽象方法 我有一个现有的解决方案,它只对所有内容使用基本类型,但是我很快发现自己在铸造方面一团糟 只有graph类必须公开,尽管其他类可以公开,因此包含嵌套在graph类中的节点和边类的解决方案是可以接受的 是否有任何方法可以将其结构化,以便所有属性都是正确的类型

本文底部是一个解决方案的示例,尽管该示例显然无效,因为它在继承时使用了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>
{

}