Using the default reference object relation to access the default values โ€‹โ€‹for properties in C #

I have an object in a hierarchy whose values โ€‹โ€‹can have the value of a parent object. Both objects are of the same type.

As an example: if the Score property is double.NaN , then the Score value should be retrieved from the object pointed to by the Parent property, but only if Parent ( Parent != null ) is set.

My question is, how can I reliably and broadly implement such a model? I have 2 options, but maybe there are more?

Option 1: Change each getter and setter property to check if the property has a given or received value, the default value, and if so, try reading it from the parent

  private double score = double.NaN; public double Score { get { return (score == double.NaN && Parent != null) ? Parent.Score : score; } set { score = (Parent != null && Parent.Score == value) ? double.NaN : value; } } 

Pros:

  • real-time atomic updates of all property values โ€‹โ€‹separately
  • Explicit default comparison

Minuses:

  • each getter and setter element must be implemented manually, which may be error prone
  • executed with every get and set

Option 2: The default implementation when loading and saving an object

  void AfterLoad() { if(Parent != null) { if(score == double.NaN) { score = Parent.Score; } // (...) } } void BeforeSave() { if(Parent != null) { if(score == Parent.Score) { score = double.NaN; } // (...) } } void AfterSave() { AfterLoad(); } 

Pros:

  • parent is used only when loading (once) and saving (twice), which improves performance

Minuses:

  • at any time, changing the parent will not affect child properties

  • Before and after changing the parent, you must process the child (to return to the new default values โ€‹โ€‹after the parent changes)

  • atomicity may be affected - during storage, the object cannot access any other thread

I am sure that many had a similar dillema when implementing the "styling" model of an object. I am looking for a clean and working solution that will also work with combining collections of child and parent objects together (using CompositeCollection?).

+4
source share
3 answers

You can use a WPF-style approach where property values โ€‹โ€‹are not stored in fields, but in a dictionary in the base class.

Thus, all properties will look like

 double Prop { get{ return (double)GetValue("Prop"); } set{ SetValue("Prop",value); } } 

And GetValue will check all parents to find the default value if it is not set for the current class.

+1
source

I dealt with a similar scenario and solved it with these two classes, I am not quite happy with this, but maybe this helps.

 public class RootProperty<T> { private T _value; public virtual T Value { get { return _value; } set { if (Equals(value, _value)) return; _value = value; } } public static implicit operator T(RootProperty<T> p) { return p.Value; } public override string ToString() { return "[RootProperty<" + typeof(T).Name + ">] " + Value; } } public class InheritedProperty<T> : RootProperty<T> { private bool _override; public bool Override { get { return _override; } set { if (value.Equals(_override)) return; _override = value; //If we now override and we had no value before, copy the value that was previously inherited for convinience if (_override && (Value == null || Value.Equals(default(T)))) Value = Parent.Value; } } public RootProperty<T> Parent { get; private set; } public override T Value { get { if (Override) { return base.Value; } if (Parent == null) throw new Exception("Parent musn't be null"); return Parent.Value; } set { Override = true; base.Value = value; } } public InheritedProperty(RootProperty<T> parent) { Parent = parent; } public override string ToString() { return "[InheritedProperty<" + typeof(T).Name + ">] " + Value; } } 

usage example

 class TestParent { public RootProperty<int> MyInt { get; private set; } public TestParent() { MyInt = new RootProperty<int>(); } } class TestChild { public InheritedProperty<int> MyInt { get; private set; } public TestChild(TestParent parent) { MyInt = new InheritedProperty<int>(parent.MyInt); } } 
+1
source

I suggest using the Modified Preview Tree Traversal to organize classes and then store them in a single List<MyClass> . You can then use LINQ to sort and search for the first nonzero value for this property. I can't talk about performance, but it might be worth it.

LINQ should look something like this:

 var node = myList.Where(x => x.LeftNumber <= target.LeftNumber && x.RightNumber >= target.RightNumber) .OrderByDescending(x => x.LeftNumber) .FirstOrDefault(x => x.Prop != double.NaN); return (node != null) ? node.Prop : double.NaN; 

x.LeftNumber <= target.LeftNumber && x.RightNumber >= target.RightNumber will receive the target node, it is the parent and all other ancestors.

OrderByDescending will sort them so that the bottom of the tree is first. You can optionally use Last() instead of OrderBy().First()

FirstOrDefault() will get the first one that actually matters, starting with the target node and processing the tree.


Edit: Here I use to rebuild a tree from parent-child relationships.

 protected static void RebuildTree() { RebuildTree(allNodes[0], 0); SaveAllNodes(); } private static int RebuildTree(Taxonomy node, int left) { node.leftNumber = left; node.rightNumber = left + 1; foreach (Taxonomy child in node.Children) { node.rightNumber = RebuildTree(child, node.rightNumber); } return node.rightNumber + 1; } 
+1
source

All Articles