Pregunta

There's a bunch of nodes in 3D space:

public class Node {
    public Vector3 Position;
    public Vector3 Size;
}

Then, there are Path objects which contain an array of nodes. A node can belong to multiple paths. A path has some metadata associated with each of its nodes. The problem is, a path's nodes should be publicly accessible but the associated metadata should stay private.

Unsatisfactory solutions:

Two arrays, a public one for nodes and a private one for metadata, associated by index. Synchronization issues.

A public wrapper type to couple a node with metadata. Doesn't keep the metadata private.

What's a better way to associate private data with array elements?

¿Fue útil?

Solución 4

The idea came from nmclean's answer and comments – a nested wrapper type.

public class Path {
    
    // wraps a node and its metadata
    private class NodeData {
        // public members visible only to parent class
        public Node Node;
        public float SomeMetadata;
    }
    
    // private array...
    private NodeData[] nodeData;
    
    // ...public method
    public Node GetNode(int index) {
        return nodeData[index].Node;
    }
}

Otros consejos

I may be misunderstanding, but what's wrong with simply having two collections?

public class Path {
    private NodeInPath[] nodesInPath;
    public Node[] nodes;
}

Although instead of wrapping the node along with metadata inside a class like NodeInPath, it would probably be more useful to have a mapping between nodes and their metadata:

public class NodeMetadata {
    public Vector3 cameraPosition;
}

public class Path {
    private Dictionary<Node, NodeMetadata> _nodeMetadataMapping;
    public Node[] nodes;
}

By the way, arrays should not be public fields. You are allowing the items to change externally without a way to respond to the changes. Unless you rebuild this mapping every time a node is accessed, it has no way of adapting to changes in the nodes collection. See this post.

You have to return an interface INode instead of the concrete class. On the interface you define only the methods and properties that are allowed to be accessible outside the path. Path itself use internally the concrete class node but only returns the interface INode. Your code could look like this :

public interface INode  {void SomeAccessableMethod(); }
internal  class Vector3  {}

internal class Node : INode
{
  public void SomeAccessableMethod() {}
  public Vector3[] CameraPositions { get; set; }
}

public class Path
{
 private readonly IList<INode> _nodesInPath = new List<INode>();

 public Path()
 {
   //Initalise all the nodes
   for(int cnt = 0; cnt < 10; cnt++)
   {
     var node = new Node();
     node.CameraPositions = new Vector3[1];
     node.CameraPositions[0] = new Vector3();
     _nodesInPath.Add(new Node());
   }
 }
 public INode[] NodesInPath
 {
   get { return _nodesInPath.ToArray(); }
 }
}

(I prefer to use a list instead of an array and the initialization is also up to you. You can also define the Node class inside of the path class. That way it is not accessible in the same assembly)

If I understand you correctly (I'm only posting the basic structure).

public class Node {
    public Vector3 position;
}

public class Path {
  private Dictionary<Node, Vector3> cameraPositions = new Dictionary<node,Vector3>();
  public List<Node> NodesInPath {get;}

  public Node AddNode(Node node, Vector3 cameraPosition);
  public Vector3 GetCameraPosition(Node node);
}

Basically the camera position belongs to your Path class (privately) and you set it foreach node individually when you add it to the path. Every path has a different set of camera positions for a given node.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top