簡體   English   中英

有什么方法可以訪問“ super”類的字段(未繼承)

[英]Is there any way to access fields of 'super' class (not inherited)

標題可能會引起誤解,因為我在搜索甚至創建適當的問題時遇到了一些麻煩,因此讓我提出一個我正在努力解決的實際問題:

我有一個Graph類。 由於圖需要節點和邊,因此我另外創建了兩個類Node (vertex)和Edge 我的結構如下所示:

class Graph
{
    List<Node> nodes;
    List<Edge> edges;

    public Graph( ... ) { /* populate lists */ }
}

class Node { ... }
class Edge { ... }

我為Node類編寫了一些方法,其中一種方法對我來說尤其成問題。 簽名:

public List<Node> GetNeighbours(List<Edge> edges) { ... }

很標准。 給定一個圖,我問一個節點:您有幾個鄰居? 我需要邊緣列表來解決它。

如何重構此代碼,以便可以在內部使用Graph屬性/字段,而不必每次都傳遞邊列表? 可能是這樣的:

public List<Node> GetNeighbours()
{
    // ...
    foreach(edge in *BASE*.edges) { ... }
}

我知道我不能使用base關鍵字,因為我在這里不需要任何繼承(為什么節點必須從圖繼承?!),嵌套類似乎也沒有幫助(無法訪問“父級”)字段)。

這段代碼現在可以正常工作,但是我覺得它並不優雅,我想體驗一個適當的解決方案。

將引用傳遞給Graph構造函數中的父類。

就像是:

class Graph
{
    private ParentType parent;

    public void Graph(ref ParentType parent)
    {
        this.parent = parent;
    }
}

然后,在GetNeighbours方法中(假設ParentType具有Edges集合屬性):

public List<Node> GetNeighbours()
{
    // ...
    foreach(var edge in parent.Edges) { ... }
}

根據您對要執行的操作的描述:

給定一個圖,我問一個節點:您有幾個鄰居?

您確定這應該是Node的方法嗎? 由於Graph包含NodesEdges因此此方法最好在Graph

public List<Node> GetNeighbours(Node node)
{
    if(!nodes.Contains(node)
    {
        return new List<Node>(); //No neighbors. Return an empty list.
    }
    // Find and return the neighbors. This method is in Graph so it
    // has access to all of Graph's internals.
}

我的理由是,由於從某種意義上說Graph是父級,並且包含Nodes ,因此Node不需要了解Graph 它的目的(單一職責)是完整的,沒有對Graph任何引用。

我將在Graph上使用類似Graph.AddNodes()Graph.AddEdges() ,以便在Graph.AddEdges()確保所有Nodes (和/或Edges )都具有所需的引用。 我在想像這樣的事情,具體取決於您的NodeEdge的型號。

class Graph
{
    List<Node> nodes;
    List<Edge> edges;

    public Graph( ... ) { /* populate lists */ }

    public void AddEdges(params Edge[] edges) {
        foreach (var edge in edges) {
            edge.Node1.Parent = this;
            edge.Node2.Parent = this;
        }
    }
}

class Node {
    public Graph Parent { get; set; }

    public List<Node> GetNeighbours()
    {
        var neighbors = new List<Node>();
        foreach(var edge in parent.Edges) { 
            if (edge.Node1 == this && !neighbors.Contains(edge.Node2)) {
                neighbors.Add(edge.Node2);
            }
            else if (edge.Node2 == this && !neighbors.Contains(edge.Node1)) {
                neighbors.Add(edge.Node1);
            }
        }
    }
}

class Edge {
    public Node Node1 { get; set; }
    public Node Node2 { get; set; }
}

這是另一種方法。 您可以使每個邊緣都知道兩端的節點,而不是傳遞父級引用。 並使每個節點了解連接到它們的邊緣。

這樣做的一個巨大優點是,您無需枚舉可能需要大量的節點/邊來查找所需的內容。 您已經有了所需的東西,因此速度更快。

這是我描述的方法的快速示例以及一些測試:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GraphModelTest
{
    class Program
    {
        static void Main(string[] args)
        {
            TestA();
            TestB();
            TestC();
        }

        private static void TestC()
        {
            //A <-> B
            //|     |
            //D <-> C
            Node a = new Node("a");
            Node b = new Node("b");
            Node c = new Node("c");
            Node d = new Node("d");
            Edge ab = a.ConnectTo(b);
            Edge bc = b.ConnectTo(c);
            Edge cd = c.ConnectTo(d);
            Edge da = d.ConnectTo(a);
            Graph g = new Graph();
            g.Nodes.Add(a);
            g.Nodes.Add(b);
            g.Nodes.Add(c);
            g.Nodes.Add(d);
            g.Edges.Add(ab);
            g.Edges.Add(bc);
            g.Edges.Add(cd);
            g.Edges.Add(da);
            Console.WriteLine(g.ToString());

            Console.WriteLine("Neighbours of B");
            foreach (Node n in b.GetNeighbours())
            {
                Console.WriteLine(n.ToString());
            }
            Console.WriteLine("Neighbours of D");
            foreach (Node n in d.GetNeighbours())
            {
                Console.WriteLine(n.ToString());
            }
        }

        private static void TestB()
        {
            //A <-> B <-> C
            Node a = new Node("a");
            Node b = new Node("b");
            Edge ab = a.ConnectTo(b);
            Node c = new Node("c");
            Edge bc = b.ConnectTo(c);
            Graph g = new Graph();
            g.Nodes.Add(a);
            g.Nodes.Add(b);
            g.Nodes.Add(c);
            g.Edges.Add(ab);
            g.Edges.Add(bc);
            Console.WriteLine(g.ToString());

            Console.WriteLine("Neighbours of B");
            foreach (Node n in b.GetNeighbours())
            {
                Console.WriteLine(n.ToString());
            }
        }

        private static void TestA()
        {
            //A <-> B
            Node a = new Node("a");
            Node b = new Node("b");
            Edge ab = a.ConnectTo(b);
            Graph g = new Graph();
            g.Nodes.Add(a);
            g.Nodes.Add(b);
            g.Edges.Add(ab);
            Console.WriteLine(g.ToString());
        }
    }

    class Edge
    {
        public Edge(string name, Node a, Node b)
        {
            Name = name;
            A = a;
            B = b;
        }

        public Node A { get; private set; }
        public Node B { get; private set; }
        public string Name { get; private set; }

        public override string ToString() => $"{Name}";
    }

    class Node
    {
        public Node(string name)
        {
            Name = name;
            connectedEdges = new List<Edge>();
        }

        public string Name { get; private set; }

        private ICollection<Edge> connectedEdges;
        public IEnumerable<Edge> ConnectedEdges
        {
            get
            {
                return connectedEdges.AsEnumerable();
            }
        }

        public void AddConnectedEdge(Edge e)
        {
            connectedEdges.Add(e);
        }

        public Edge ConnectTo(Node n)
        {
            //Create the edge with references to nodes
            Edge e = new Edge($"{Name} <-> {n.Name}", this, n);
            //Add edge reference to this node
            AddConnectedEdge(e);
            //Add edge reference to the other node
            n.AddConnectedEdge(e);
            return e;
        }

        public IEnumerable<Node> GetNeighbours()
        {
            foreach (Edge e in ConnectedEdges)
            {
                //Have to figure which one is not this node
                Node node = e.A != this ? e.A : e.B;
                yield return node;
            }
        }

        public override string ToString() => $"{Name}";
    }

    class Graph
    {
        public Graph()
        {
            Nodes = new List<Node>();
            Edges = new List<Edge>();
        }

        public ICollection<Node> Nodes { get; set; }
        public ICollection<Edge> Edges { get; set; }

        public override string ToString()
        {
            StringBuilder str = new StringBuilder();

            str.AppendLine("Graph:");
            str.AppendLine("Nodes:");
            foreach (Node n in Nodes)
            {
                str.AppendLine(n.ToString());
            }
            str.AppendLine("Edges:");
            foreach (Edge e in Edges)
            {
                str.AppendLine(e.ToString());
            }

            return str.ToString();
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM