This question already has answers here:
Is there a way to reach a `protected` member of another object from a derived type?
(7 answers)
Closed 9 years ago.
I want to organise a scene graph.
I have general class SceneNode:
public class SceneNode
{
protected SceneNode prev, next;
protected SceneNodeContainer parent;
public SceneNode Parent { get { return parent; } }
public SceneNode PreviousNode { get { return prev; } }
public SceneNode NextNode { get { return next; } }
}
I also have class SceneNodeContainer, which is like this:
public class SceneNodeContainer : SceneNode
{
SceneNode firstChild, lastChild;
public SceneNode FirstChild { get { return firstChild; } }
public SceneNode LastChild { get { return lastChild; } }
public void Add(SceneNode node)
{
Debug.Assert(node != null);
Debug.Assert(node.parent == null);
node.parent = this;
node.prev = lastChild;
node.next = null;
if (lastChild == null)
{
lastChild = node;
firstChild = lastChild;
}
else
{
lastChild.next = node;
lastChild = node;
}
}
public void Remove(SceneNode node)
{
Debug.Assert(node != null);
Debug.Assert(node.parent == this);
//unlink node
if (node.next != null)
node.next.prev = node.prev;
if (node.prev != null)
node.prev.next = node.next;
if (node == firstChild)
firstChild = node.next;
if (node == lastChild)
lastChild = node.prev;
node.parent = null;
node.next = null;
node.prev = null;
}
}
IntelliSense says that node.parent and other protected fields cannot be accessed from SceneNodeContainer. How can I overcome this?
You can't, because of the way protected works - it only allows access to protected fields of objects which are known to be of the child type (or a subtype). So if node were a SceneNodeContainer variable, you'd have access to the fields - but otherwise, you don't.
From section 3.5.3 of the C# 4 spec:
When a protected instance member is accessed outside the program text of the class in which it is declared, and when a protected internal instance member is accessed outside the program text of the program in which it is declared, the access must take place within a class declaration that derives from the class in which it is declared. Furthermore, the access is required to take place through an instance of that derived class type or a class type constructed from it. This restriction prevents one derived class from accessing protected members of other derived classes, even when the members are inherited from the same base class.
(As an aside, I'd personally avoid protected fields anyway. I make non-constant fields private in almost all cases.)
use protected internal instead of protected then you can access from sub classes of same assembly.
public class SceneNode
{
protected internal SceneNode prev, next;
protected internal SceneNodeContainer parent;
public SceneNode Parent { get { return parent; } }
public SceneNode PreviousNode { get { return prev; } }
public SceneNode NextNode { get { return next; } }
}
Related
Could somebody tell me please, how in children class correctly override property declared in parent class?
I am trying to override "Tasks" property. In child class it should return list of items of type "ICheckListTask".Part of code:
Parent class:
internal class CBaseTaskList : IBaseTaskList
{
protected List<IBaseTask> _tasks = new List<IBaseTask>();
virtual protected List<IBaseTask> Tasks
{
get { return _tasks; }
set { _tasks = value; }
}
public virtual IBaseTask this[int index]
{
get { return Tasks[index]; }
set { Tasks[index] = value; }
}
public virtual void Add(IBaseTask newTask)
{
Tasks.Add(newTask);
}
Children class:
internal class CCheckListTaskList : CBaseTaskList, ICheckListTaskList
{
override protected List<ICheckListTask> Tasks
{
get { return (List<ICheckListTask>)_tasks; }
set { Tasks = value; }
}
public void WhereIsDone()
{
Tasks = new List<ICheckListTask>(Tasks.Where(x => x.IsDone == true));
}
In children class I get error what type of CCheckListTaskList.Task must be not "List<ICheckListTask>", but "List<IBaseTask>".
How to correctly do what I want to do?
I think you should use "new" instead of "override"
I have a class:
public class A
{
private IB link;
public IB Link
{
get { return link; }
set
{
link = value;
b.Link = this;
}
}
...
}
and an interface:
public interface IB
{
A Link { get; set; }
}
I will use it like this:
public class B1 : IB, Button
{
public A Link { get; set; }
...
}
public class B2 : IB, TextBox
{
public A Link { get; set; }
...
}
b1 = new B1();
b2 = new B2();
A a = new A();
a.Link = b1;
...
a.Link = b2;
But I have to encapsulate the IB.Link property, it should changed only in the A class (along with the A.Link property). Is this possible?
Update:
Sorry for ambiguity of this example. My real code is too large and not finished: I have a structure of nodes. Each node has a link to Control. So, visual structure of controls can be constructed. We can manage the controls from nodes, but not get access to node from control, for example, from OnMouseClick method. We need have back reference - the IMyControl.OwnerNode property. IMyControl is interface that contains only this property. So, we can create "MyControl : IMyControl, Control" class and implement into it mouse click logic. When we assign control to node, both references must be created, direct and back, but it take place in code of node class, not in MyControl and IMyControl code. Property field in IMyControl interface must be accessible for write from NodeClass and unaccessible for write from derived classes. That i am trying to accomplish here.
If I understand you correctly, you can use this draft:
class Node
{
public ControlWrapper Link { get; set; }
}
abstract class ControlWrapper
{
private readonly Node _node;
private readonly Control _control;
public Node Node
{
get { return _node; }
}
public Control Control
{
get { return _control; }
}
public ControlWrapper(Node node, Control control)
{
if (node == null)
throw new ArgumentNullException("node");
if (control == null)
throw new ArgumentNullException("control");
_node = node;
_control = control;
}
}
class ControlWrapper<TControl> : ControlWrapper
where TControl : System.Windows.Forms.Control
{
public TControl Control
{
get { return (TControl)base.Control; }
}
public ControlWrapper(Node node, TControl control)
: base (node, control)
{
}
}
class Program
{
static void Main(string[] args)
{
Node n1 = new Node();
n1.Link = new ControlWrapper<TextBox>(n1, new TextBox());
Node n2 = new Node();
n2.Link = new ControlWrapper<Button>(n2, new Button());
}
}
Abstract class ControlWrapper provides you with back-link to node (you can't encapsulate logic in interface, so abstract class goes here), typed derived generic class provides constructor for creating actual implementations of control-wrappers.
If you want this relation automatically force its consistency, you should write code like this:
class Program
{
static void Main(string[] args)
{
Node n1 = new Node();
n1.SetControl(new TextBox());
Node n2 = new Node();
n2.SetControl(new Button());
}
}
class Node
{
private ControlWrapper _link;
public ControlWrapper Link
{
get { return _link; }
}
public void SetControl<TControl>(TControl control)
where TControl : System.Windows.Forms.Control
{
ControlWrapper prevLink = Link;
if (prevLink != null)
prevLink.Dispose();
_link = new ControlWrapper<TControl>(this, control);
}
}
// microsoft basic dispose pattern
// http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx#basic_pattern
abstract class ControlWrapper : IDisposable
{
private readonly Node _node;
private readonly Control _control;
public Node Node
{
get { return _node; }
}
public Control Control
{
get { return _control; }
}
public ControlWrapper(Node node, Control control)
{
if (node == null)
throw new ArgumentNullException("node");
if (control == null)
throw new ArgumentNullException("control");
_node = node;
_control = control;
}
#region IDisposable Members
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_control != null)
_control.Dispose();
}
}
}
class ControlWrapper<TControl> : ControlWrapper
where TControl : System.Windows.Forms.Control
{
public TControl Control
{
get { return (TControl)base.Control; }
}
public ControlWrapper(Node node, TControl control)
: base (node, control)
{
}
}
I am working on trees and I want to access object parameters, methods in linlinkilist->Node->object->object but couldn't do it.
What I am trying to do is put collection group of object in tree, and search this object
So Linked List have 2 kind of objects parent and child and these objects construct get another object, I am trying to search and find this collisionObject but I could not access it
I try to use list.head.data. but I couldn't success. I don't want to change Linked List data parameter as CollisionObject class because I want to use this Linked List for every other object normally I do parameter that I want to use, as public or get;set; to access object within another object like list.head.data its stuck here; I could not access parameters or methods in data and also object with in data
public class Child
{
private CollisonObject colobj;
public Child(CollisonObject c) { this.colobj = c; }
public Child(ref CollisonObject o) { this.refcolobj = o; }
public void draw(SpriteBatch sb)
{
colobj.draw(sb);
}
}
public class Parent
{
CollisonObject pcolobj;
private LinkList list = new LinkList();
public Parent(CollisonObject o) { this.pcolobj = o; }
public void RenderPanel(SpriteBatch sb)
{
//Console.WriteLine("Child Control for Panel(" + Name + ") Render start");
foreach (Object item in ChildControls)
{
Parent objPanel = item as Parent;
if (objPanel == null)
{
Child objTextbpx = item as Child;
if (objTextbpx == null)
{ break; }
objTextbpx.draw(sb);
}
else
{
objPanel.draw(sb);
objPanel.RenderPanel(sb);
}
}
// Console.WriteLine("Child Control for Panel(" + Name + ") Render End");
}
public void CreateChildControl(Object control)
{
list.AddtoBegining(control);
}
public void DeleteChildControl(Object control)
{
ChildControls.Remove(control);
}
public void draw(SpriteBatch sb)
{
pcolobj.draw(sb);
}
public Object Search(object o)
{ CollisonObject co = (CollisonObject)o;
co = (CollisonObject)list.head.data;
ChildControls.Remove(co.Name);
return o;
}
}
I am trying to delete a Node from a linked list. Below is the code I have tried.
public class Node : IDisposable
{
public int Value { get; set; }
public Node Next { get; set; }
public Node(int value)
{
this.Value = value;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Next.Dispose();
}
}
}
public class LinkedList
{
Node head;
public void CreateList()
{
Node node1 = new Node(1);
Node node2 = new Node(2);
Node node3 = new Node(3);
head = node1;
node1.Next = node2;
node2.Next = node3;
}
public void DeleteLastItem()
{
Node prevNode = head;
Node nextNode = head;
while (nextNode.Next != null)
{
prevNode = nextNode;
nextNode = nextNode.Next;
}
prevNode.Next = null;
nextNode.Dispose();
}
}
I wanted to dispose the nextNode (which is nothing but the last node. And it will not be part of the Linked List).
When I try above code, I am getting below exception:
Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
How can I proceed here ? How can I dispose a Node object?
In your Dispose(bool) method, you can only dispose the next node if there is one. Check for a null reference before you attempt that:
protected virtual void Dispose(bool disposing) {
if (disposing) {
if (Next != null) {
Next.Dispose();
}
}
}
I guess you should simply check if Next is not null before calling Dispose on it.
When the Dispose method is called on any node, you manually call the next one so one you will reach the last one, the Next property will be null therefore you get this exception.
Considering the code you gave, I don't see why you would need your node to be disposable. It is only necessary if you use non managed resources which is not the case in the code you gave (but maybe you simplified it for the question).
In your Dispose logic, check for NULL:
public class Node : IDisposable
{
public int Value { get; set; }
public Node Next { get; set; }
public Node(int value)
{
this.Value = value;
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (Next != null) // <-- new code here
{
Next.Dispose();
}
}
}
}
I'm currently struggling with the implementation of a set of file system classes. I guess this calls for the composite pattern if I'm not mistaken. So I set up the following classes:
An abstract class Node which has a reference to its parent folder and two classes Folder and File that implement Node. A folder contains a collection of all its children and methods to add and remove children.
The thing is, I can't figure out how to implement all the methods properly. In all the examples I have seen there is no reference to the parent in the children. How can the AddChild method ensure that the child's parent reference is set correctly? I solved that by checking whether child.Parent has already been set to the folder or it throws an ArgumentException. The matter is further complicated by the fact that AddChild might also throw an exception like DuplicateNameException or something. So my methods look like this now:
File.AddTo(Folder folder) {
this.Parent = folder;
try {
folder.AddChild(this);
} catch {
this.Parent = null;
throw;
}
}
Folder.AddChild(Node child)
{
if(child.Parent != this)
throw new ArgumentException(...);
...
}
Now I have this ugly AddTo method and cannot do something like someFolder.AddChild(new File(...)). I wonder how it was implemented with ListViewItem for instance. There I can just do someListView.Items.Add(new ListViewItem(...)).
My solution works, but I'm not convinced that it's the right way to do this. Maybe someone has a better solution or can point me to a good example. Thanks in advance.
EDIT: Minimal full class definitions below.
abstract class Node
{
public Folder Parent { get; protected set; }
public string Name { get; private set; }
public Node(string name) {
Parent = null;
Name = name;
}
}
class Folder : Node {
private Dictionary<string, Node> _children;
public Folder(string name) : base(name) {
// Other initializations here...
}
public void AddChild(Node child) {
if(child is Folder)
((Folder)child).Parent = this; // Damn, doesn't work for files!!!
else if(child.Parent != this)
throw new ArgumentException();
if(_children.ContainsKey(child.Name))
throw new DuplicateNameException();
_children[child.Name] = child;
}
}
class File : Node {
public File(string name) : base(name) {
// Other initializations here...
}
public void AddTo(Folder folder) {
Parent = folder;
try {
folder.AddChild(this);
} catch {
Parent = null;
}
}
}
How about doing it the other way around:
Folder.AddChild(Node child)
{
child.Parent = this;
this._children.Add(child); // or what ever your doing to store the children
...
}
If you're adding a child to the parent, that should be done through a method on parent. Parent can then confirm/validate its own state and that its preconditions are satisfied. It's not up to a node to figure out whether its parent is valid -- let the parent do that.
So, by way of code, you have something like:
public class Node
{
public string Name { get; set; }
public abstract void Add(Node child);
protected abstract void CreateOnDisk();
}
public class File
{
public override void Add(Node child)
{
//No op, since you can't add a child to a file
}
protected override void CreateOnDisk()
{
File.Create(this.Name);
}
}
public class Directory
{
public override void Add(Node child)
{
child.Name = Path.Combine(this.Name, child.Name);
child.CreateOnDisk();
}
protected override CreateOnDisk()
{
Directory.Create(this.Name);
}
}
I just freelanced a bit off the top of my head, but that's to give an idea. I really think there's no need to keep track of your parent, and I think that's going to turn out in the end to be a fairly cumbersome solution.
When I implement bidirectional associations, I usually move all association maintenance to one of the sides. In this case, I'd chose Folder.
public abstract class Node
{
public Folder Parent { get; set; }
public string Name { get; set; }
public abstract long Size { get; }
}
public class File : Node
{
private long _size;
public override long Size
{
get { return _size; }
}
public void AddTo(Folder folder)
{
folder.Add(this);
}
public void RemoveFrom(Folder folder)
{
folder.Remove(this);
}
}
public class Folder : Node
{
private List<Node> _children = new List<Node>();
public void Add(Node node)
{
if (node.Parent == this)
return; // already a child of this folder
_children.Add(node);
node.Parent = this;
}
public void Remove(Node node)
{
if (node.Parent != this)
return; // not a child of this folder
_children.Remove(node);
node.Parent = null;
}
public override long Size
{
get { return _children.Sum(node => node.Size); }
}
}
PS try to eliminate bidirectional association, it adds lot of headache.
UPDATE
With unidirectional association you have simple code, without ugly Folder field in Node class (I hate when base class depends on its child). Also no headache with adding/removing files.
public abstract class Node
{
public string Name { get; set; }
public abstract long Size { get; }
}
public class File : Node
{
private long _size;
public override long Size
{
get { return _size; }
}
}
public class Folder : Node
{
private List<Node> _children = new List<Node>();
public void Add(Node node)
{
if (_children.Contains(node))
return;
_children.Add(node);
}
public void Remove(Node node)
{
if (!_children.Contains(node))
return;
_children.Remove(node);
}
public override long Size
{
get { return _children.Sum(node => node.Size); }
}
}
AddChild() is a method on the parent.
Thinking about the purpose of the method, and your desire to maintain a reference to the parent in the child, you need to expose a property on the child that can be set by the parent, presumably in the AddChild method.
public abstract class Node
{
private Node parent;
internal void SetParent(Node parent)
{
this.parent = parent;
}
}
public class Folder : Node
{
void AddChild(Node child)
{
this.children.Add(child);
child.SetParent(this); // or, you could use a C# Property
}
}
public class File : Node
{
}
The child knows how to establish its parent; the parent knows how to adopt a child.