Compact syntax to create tree structure in C# - c#

I would like to create a somewhat complex tree structure in code, in a concise manner. Right now I'm using this (simplified):
var root = new Tree();
var c1 = root.Add("1");
var c2 = root.Add("2");
var c21 = c2.Add("2-1");
var c22 = c2.Add("2-2");
//...
Average node width is 4, tree height is about 5, so the above process is very tedious, not to mention poorly maintainable.
Let us assume the nodes are not accessed by name later. The tree/node classes can be adjusted as necessary. Performance can be disregarded. Creation via XML or similar is not possible (the node constructor is quite a bit more complicated in reality).
What I'm looking for is something like the following, but I'm not sure how this could be implemented in C#. In Java, this would be possible via anonymous classes, which cannot be used for this purpose in C#.
var root = new Tree() {
Add("1");
Add("2") {
Add("2-1");
Add("2-2");
};
}
The best solution I could think of would use run-on declaration similar to the following, which I think is poorly maintainable:
// AddXxx returns the added node
var root = new Tree()
.Add("1")
.AddSibling("2")
.Add("2-1")
.AddSibling("2-2")
.AddParent("3")
.Add("3-1")
Or alternatively:
// Add now always adds a sibling, Children/Parent steps up/down in the hierarchy
var root = new Tree()
.Children
.Add("1")
.Add("2")
.Children
.Add("2-1")
.Add("2-2")
.Parent
.Add("3")
.Children
.Add("3-1")

I will do something like this:
public class Tree
{
public string Name { get; private set; }
public List<Tree> Trees { get; private set; }
public Tree(string name)
{
this.Name = name;
this.Trees = new List<Tree>();
}
public Tree(string name, params Tree[] nodes)
: this(name)
{
if (nodes == null || !nodes.Any()) return;
Trees.AddRange(nodes);
}
}
Then use it like this:
var trees = new List<Tree>
{
new Tree("1"),
new Tree("2",
new Tree("2-1"),
new Tree("2-2",
new Tree("2-2-1"),
new Tree("2-2-1")
)
),
new Tree("3",
new Tree("3-1")
)
};
I was inspired to this by XElement constructor which faciltate XML nodes creation with more readability. If you are working with XML then I recommend to use that class.

You can use a collection initializer:
class Node : IEnumerable<Node> // implement interface to taste
{
public Node(string name)
{
...
}
public void Add(Node n)
{
...
}
}
var root = new Node("x")
{ // Each item in this {} is passed to Add
new Node("y-1")
{
new Node("z-1"),
new Node("z-2")
},
new Node("y-2")
};

A conventional way to do this is with a collection initalizer. I'm not a fan, because this means you need to implement an Add method, and that means you need to implement a mutable Tree interface, which is (IMHO) a hassle that makes many conventional tree algorithms unsafe. (you could also implement freezable TreeBuilder, but that's just as much hassle).
I prefer to list all tree nodes at construction time, and with C# 6's using static you can do this quite cleanly.
Linqpad query:
void Main()
{
Node("test",
Node("kid"),
Node("kid2",
Node("grandchild")
),
Node("kid3",
Node("grandchild2"),
Node("grandchild3")
)
)
.ToString().Dump();
}
public static class Tree
{
public static TreeNode<T> Node<T>(T val, params TreeNode<T>[] kids)
=> new TreeNode<T>(val, kids);
}
public struct TreeNode<T>
{
public readonly T NodeValue;
public readonly IReadOnlyList<TreeNode<T>> Kids;
public TreeNode(T val, TreeNode<T>[] kids)
{
NodeValue = val;
Kids = kids;
}
public override string ToString()
=> $"\n{NodeValue}:{string.Join("", Kids).Replace("\n", "\n ")}";
}
which prints:
test:
kid:
kid2:
grandchild:
kid3:
grandchild2:
grandchild3:
Note that reinterpreting an array as IReadOnlyList doesn't protect you from nasty callers that mutate params arrays after constructions, which is likely fine in a normal project, but possibly not so hot for a public api - YMMV.

Related

How to define an inheritable tree class in C# to build tree like data structure made from different class types?

I‘Ve been reading around this topic for some time, but I simply don't know the C# syntax well enough. Hopefully this is clear to you and you are willing to help me out. The examples I found are tree structures of the same type or class, which are not what I need here.
In short, I want to be able to define an arbitrary class, like NodeClassA, NodeClassB, NodeClassC below and be able to attach any number of these to each other to form a tree data structure as illustrated arbitrarily below.
Each Node should be able to access its parent.
Can anyone help properly define the MyTreeClass below?
NodeClassB
__NodeClassC
__NodeClassA
____NodeClassB
____NodeClassB
____NodeClassA
__NodeClassA
____NodeClassC
__NodeClassB
__NodeClassC
class MyTreeClass
{
public void AddChild(T NodeClassX) { }
public T GetChild() { }
}
class NodeClassA:MyTreeClass
{
public void foo(int a) { }
}
class NodeClassB : MyTreeClass
{
public void foo(int b) { }
}
class NodeClassC : MyTreeClass
{
public void foo(int c) { }
}
You might be looking for the composite pattern which is a common way to model tree structures, e.g. a file system where you have a leaves (files) and containers (folders) and containers can contain other containers or leaves themselves.
In your case, at least the way you described it so far, it is a bit simpler because there is no behavioral difference between those nodes. So for your structure, the nodes can actually be shallow and you only need to implement the composition within your base class. In that way, you don’t have leaves but only (different) containers.
public abstract class BaseNode
{
public IList<BaseNode> Children
{ get; } = new List<BaseNode>();
}
public class NodeClassA : BaseNode { }
public class NodeClassB : BaseNode { }
public class NodeClassC : BaseNode { }
And then you can already build your structure.
This is not possible in a strict type safe way because type safety is ensured at compile time, which requires the types to be statically declared. But the tree is built dynamically at runtime with different node types.
The way to go is to have a static node data type which can be generic. Different types of data can be derived form a given base data type. Use polymorphy to work with them. I.e. use the same set of methods with different implementations.
public class TreeNode<T>
{
public T Data { get; set; }
private List<TreeNode<T>> _children = new List<TreeNode<T>>();
public IEnumerable<TreeNode<T>> Children => _children;
public TreeNode<T> AddChild(T data)
{
var node = new TreeNode<T> { Data = data };
_children.Add(node);
return node;
}
public void VisitPreOrder(Action<T, int> action, int level)
{
action(Data, level);
foreach (TreeNode<T> node in Children) {
node.VisitPreOrder(action, level + 1);
}
}
}
public class Tree<T>
{
public TreeNode<T> Root { get; } = new TreeNode<T>();
public void VisitPreOrder(Action<T, int> action)
{
Root.VisitPreOrder(action, 0);
}
}
Now you can have data classes that are totally unrelated to the tree:
public class A
{
public int Index { get; set; }
public virtual void PrintLine()
{
Console.WriteLine($"A {Index}");
}
}
public class B : A
{
public override void PrintLine()
{
Console.WriteLine($"B {Index}");
}
}
public class C : B
{
public override void PrintLine()
{
Console.WriteLine($"C {Index}");
}
}
Create a tree structure from your example
TreeNode<A> node;
var tree = new Tree<A>();
tree.Root.Data = new B { Index = 0 }; // NodeClassB
tree.Root.AddChild(new C { Index = 1 }); // __NodeClassC
node = tree.Root.AddChild(new A { Index = 2 }); // __NodeClassA
node.AddChild(new B { Index = 3 }); // ____NodeClassB
node.AddChild(new B { Index = 4 }); // ____NodeClassB
node.AddChild(new A { Index = 5 }); // ____NodeClassA
node = tree.Root.AddChild(new A { Index = 6 }); // __NodeClassA
node.AddChild(new C { Index = 7 }); // ____NodeClassC
tree.Root.AddChild(new B { Index = 8 }); // __NodeClassB
tree.Root.AddChild(new C { Index = 9 }); // __NodeClassC
Because each data type (base type or derived type) does its own thing appropriate for its type, you don't need to know its exact type. This is called polymorphy. This prints the tree structure:
tree.VisitPreOrder((item, level) => {
Console.Write(new string('_', 4 * level));
item.PrintLine();
});
B 0
____C 1
____A 2
________B 3
________B 4
________A 5
____A 6
________C 7
____B 8
____C 9
Note that you don't need to know the concrete data type of T when declaring the Tree<T> and TreeNode<T> classes since T is generic. You could as well declare
var stringTree = new Tree<string>();
var intTree = new Tree<int>();
Just make your arbitrary class inherit or compose a collection of some kind. For example your arbitrary classes could all be lists. The augmentation would be that the add method sets the child's parent and that the parent is a property.

Initializing an array of generic collections with each a different generic argument

During the development of one of my projects, I encountered an issue regarding generic types.
The project requires me to write a class that would act as a source of list objects. Suppose I had the following class:
public class TablesProvider
{
private readonly List[] _tables;
public TablesProvider()
{
// initialize the tables var here....
}
public List<TItem> GetTable<TItem>()
{
return (List<TItem>)_tables.Single(x => x is List<TItem>);
}
}
This class obviously doesn't work, because the List type is a generic type and therefore the generic arguments should be specified.
So I made an abstract type called MyList, that would be derived by a more specific type MyList<TItem> in order to escape this requirement, and edited the TablesProvider a little.
public class TablesProvider
{
private readonly MyList[] _tables;
public TablesProvider()
{
// initialize the tables var here....
}
public MyList<TItem> GetTable<TItem>()
{
return (MyList<TItem>)_tables.Single(x => x is MyList<TItem>);
}
}
public abstract class MyList
{
// ...
}
public class MyList<TItem> : MyList, IList<TItem>
{
private readonly List<TItem> _elements = new List<TItem>();
public TItem this[int index]
{
get { return _elements[index]; }
set { _elements[index] = value; }
}
// ...
}
This works quite well. There is only one problem left. Suppose I had 45 different collections, each defined with a different generic argument. What would be the best way of initializing all of those collections? I cannot use a for loop here, since generic parameters are specified at compile-time and not at runtime, and therefore a construction like this wouldn't be possible:
for (int i = 0; i < 45; i++)
_tables[i] = new MyList<GenericParameters[i]>();
My ultimate goal is to have the luxury to just do something like this...
var table = _tablesProvider.GetTable<SomeClass>();
var element = table[3];
var propertyValue = element.SomeProperty;
... without the need to cast the variable element in order to access its type-specific members.
It is probably worth mentioning that the amount of different list objects is fixed to 45. This will not change. In theory, I could initialize the array line by line, or have 45 properties or variables instead. Both of these options, however, sound as a rather cheap solution to me, but I will accept one of them if there is no other way.
Any of you got some ideas? Am I doing this completely wrong? Should I consider an other structure?
Thanks in advance.
Yes, it is possible to do what you are describing if you use reflection.
Supposing that your hypothetical GenericParameters array is an array of Types (since you can't have an array of type identifiers), you can define this helper function:
private MyList MakeList(Type t)
{
return (MyList)Activator.CreateInstance(typeof(MyList<>).MakeGenericType(t));
}
And that will allow you to do this:
public TablesProvider()
{
var GenericParameters = new[] { typeof(string), typeof(int), typeof(DateTime) };
_tables = new MyList[GenericParameters.Length];
for (int i = 0; i < GenericParameters.Length; i++)
{
_tables[i] = MakeList(GenericParameters[i]);
}
}
You can even use LINQ if you want:
public TablesProvider()
{
var GenericParameters = new[] { typeof(string), typeof(int), typeof(DateTime) };
_tables = GenericParameters.Select(MakeList).ToArray();
}
Previous answer:
Well, the reality is that you're going to have a list of 45 different types somewhere, which pretty much means you're going to have 45 different lines of similar code. So one could say the goal is to make those lines as concise as possible.
One way to do so would be to add a helper function:
private void AddTable<T>()
{
_tables.Add(new MyTable<T>());
}
(this assumes changing _tables to a List<MyTable>)
Then you could just do:
AddTable<Type1>();
AddTable<Type2>();
AddTable<Type3>();
AddTable<Type4>();
this implementation works
public class TablesProvider
{
private readonly List<object> _tables;
public TablesProvider()
{
_tables = new List<object>();
}
public IList<TItem> GetTable<TItem>()
{
var lst = (List<TItem>)_tables.SingleOrDefault(x => x is List<TItem>);
if (lst == null)
{
lst = new List<TItem>();
_tables.Add(lst);
}
return lst;
}
}
it creates List of TItem when necessary; next time it returns the same list for TItem. it is lazy initialization
so you can do invoke
var table = _tablesProvider.GetTable<SomeClass>();
without any code like this:
for (int i = 0; i < 45; i++)
_tables[i] = new MyList<GenericParameters[i]>();
it is not ThreadSafe

Is there a jQuery extend in c#?

var _Contact = new ContactLstModel {
ContactName="xxxxxx",
EmailAddr="yyyyyy",
ContactNo="ddddddd",
SelectedContactType="dddd"
};
var _ContactOption= new ContactLstModel{
ContactType= new List<SelectListItem>(){
new SelectListItem{
Text="sss",Value="ddd"
}
}
};
as you can see both are of the same model ContactLstModel. Now how do I combine both into one?
Like in jQuery, we have $.extend(dest,source);
Is there an equivalent in C#?
There is not a built-in equivalent of $.extend in C# and .NET 4.5.
However you can find many examples of people trying to achieve that kind of behavior using reflection in .NET. There are others who use serialization (JSON.NET etc.) to achieve similar behaviors . Another approach would be to use IOC containers like Automapper.
Here is an example how to merge your first object into the second object using Automapper IOC:
var expr = Mapper.CreateMap<ContactLstModel, ContactLstModel>().ForMember("ContactType", (conf) => { conf.Ignore(); });
var merged = Mapper.Map<ContactLstModel, ContactLstModel>(_Contact, _ContactOption);
With Automapper you can control how to map each single property from source to destination.
If you don't want external library dependencies, and want full control you can use a pure Reflection approach.
For example you could use something similar as the CopyValues method from this link and merge the second object properties with the first one using reflection.
CopyValues<ContactLstModel>(_Contact, _ContactOption);
So this line of code will copy the ContactType property values from the second object into the first one.
CopyValues uses reflection to loop through the properties of the objects:
public static void CopyValues<T>(T target, T source)
{
Type t = typeof(T);
var properties = t.GetProperties().Where(prop => prop.CanRead && prop.CanWrite);
foreach (var prop in properties)
{
var value = prop.GetValue(source, null);
if (value != null)
prop.SetValue(target, value, null);
}
}
Of course this does not support everything jquery extend does (merging, shallow and deep cloning into a new object etc.), but it can satisfy your current needs. You can extend on these principles and build a more comprehensive solution.
However have in mind that C# is not a language like Javascript, and the cost of doing reflection is much higher in C#, while in Javascript the properties of a prototype can be listed with a cheap for-in iteration, or with a call to Object.keys().
You could do it with an extension method:
public static class ContactModelExtensions {
public static ContactModel Extend(this ContactModel first, ContactModel replacement) {
if (!replacement.ContactsName.IsNullOrEmpty()) // or whatever criteria you want
{
first.ContactsName = replacement.ContactsName;
}
// similar assignment for all other properties
return first; // since we return the first one, properties not set in override
// will be untouched
}
}
Now, you can just
var extendedContact = _Contact.Extend(_ContactOptions);
to get it done.
You can use some frameworks for do it. For example with ValueInjecter:
public class NoNullsInjection : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name
&& c.SourceProp.Value != null;
}
}
class A
{
public string a { get; set; }
public string b { get; set; }
}
static void Main(string[] args)
{
A a1 = new A() { a = "123" };
A a2 = new A() { b = "456" };
A c = new A();
c.InjectFrom(new NoNullsInjection(),a1,a2);
// "c" now have a="123", b="456"
}

How to break apart multiple levels of member access

Let's assume that I have these dummy classes defined:
public class MyObject
{
public InterestingFact InterestingFact { get; set; }
}
public class InterestingFact
{
public Detail Detail { get; set; }
}
public class Detail
{
public string Information { get; set; }
}
I also have an instance of MyObject:
var obj = new MyObject() { InterestingFact = new InterestingFact() };
If I want to try to access the Information property, I could do something like this:
string info = null;
if (obj != null
&& obj.InterestingFact != null
&& obj.InterestingFact.Detail != null)
{
info = obj.InterestingFact.Detail.Information;
}
Ignoring, for the sake of this discussion, the Law of Demeter, this is not a whole lot of fun every time I want to access something deep within an object I have. I can, of course, create an extension method:
public static U NullOr<T, U>(this T target, Func<T, U> selector)
{
if (EqualityComparer<T>.Default.Equals(target, default(T)))
{
return default(U);
}
return selector(target);
}
This makes selecting the data a little easier:
// Here I have a null of type string.
var info = obj.NullOr(o => o.InterestingFact).NullOr(f => f.Detail).NullOr(d => d.Information);
However, this is still a little long winded. Ideally, I'd like to do something more like this:
// Here I should still have a null of type string.
var info = obj.NullOr(o => o.InterestingFact.Detail.Information);
I've never worked with Expressions; if I take in an Expression<Func<T, U>> instead of the Func<T, U> in NullOr, it looks to me like it is one member access rather than three. Is there a way to approach the above, or is this formulation out of reach?
(There's also, of course, the concern with the last fomulation that the expression sent in could be something other than just chained member access..)
About the simplest way you can achieve the desired result with an extension method is the following.
public static class ExtensionMethods
{
public static TR DefaultIfNull<T, TR>(this T source, Expression<Func<T, TR>> expr, TR defaultValue = default(TR))
{
TR result = defaultValue;
try
{
result = expr.Compile().Invoke(source);
}
catch (NullReferenceException)
{
// DO NOTHING
}
return result;
}
}
And here is some example usages of the above
var info1 = obj.DefaultIfNull(x => x.InterestingFact.ToString(), "Null1");
var info2 = obj.DefaultIfNull(x => x.InterestingFact.Detail.ToString(), "Null2");
var info3 = obj.DefaultIfNull(x => x.InterestingFact.Detail.Information);
Note that this is not the BEST solution as it doesn't check individual expression nodes for null, so if any node in the tree happens to internally generate an NullReferenceException then the default value would be returned instead of the exception being thrown. However, for general and simple usage this is probably the optimal solution (mostly for its simplicity).

Importing XML to Objects Recursively

I am trying to write a method which uses reflection in order to get the properties and set their values while traversing XElement:
Lets say I have a class like this which only provides me XML value to be parsed:
class XMLController
{
public string XML
{
get{
return #"<FieldGroup name='People' count='20'>
<Fields>
<Field Name='Jon' LastName='McFly'/>
<Field Name='Michael' LastName='Jackson'/>
</Fields>
</FieldGroup>";
}
}
}
And this is how my Objects look like:
class FieldGroup
{
public string Name {get;set;}
public string Count {get;set;}
public IEnumerable<Field> Fields {get;set;}
}
class Field
{
public string Name {get;set;}
public string LastName {get;set;}
}
The mapper method traverses XElement and since the Node names are matching names with the Objects I am thinking this helps little more but I haven't come up with something really useful. I don't want to pass the type but rather, the method will work with almost every XML passed in with the same format.
All it knows the fact that the XML nodes and attributes are matching names.
This is what I've done but didn't really worked:
class XMLObjectMapper
{
public T Map<T>(XElement element) where T: class, new()
{
T entity = (T) Activator.CreateInstance(typeof(T));
if(element.HasAttributes)
{
MapXMLAttributesToObject<T>(element,entity);
}
if(element.HasElements)
{
foreach (var childElement in element.Elements())
{
//if the child element has child elements as well, we know this is a collection.
if(childElement.HasElements)
{
var property = GetProperty<T>(childElement.Name.LocalName);
property.SetValue(entity,new List<property.PropertyType>());
Map<T>(childElement);
}
else
{
var property = GetProperty<T>(childElement.Name.LocalName);
var type = Activator.CreateInstance(property.PropertyType);
type.Dump();
}
}
}
return entity;
}
private void MapXMLAttributesToObject<T>(XElement element, T entity)
{
foreach(XAttribute attribute in element.Attributes())
{
var property = GetProperty<T>(attribute.Name.LocalName);
property.SetValue(entity,attribute.Value);
}
}
private PropertyInfo GetProperty<T>(string propertyName)
{
return typeof(T).GetProperty(propertyName,BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
}
}
You're on the right track, but as you've noticed, you've got some errors.
The following piece of code doesn't compile because you can't use a value (property.PropertyType) in place of a type name. C# is a statically typed language, so types have to be known at compile time rather than being in variables:
new List<property.PropertyType>()
However, if you use reflection, you can choose the types at runtime. We can do this instead:
Activator.CreateInstance(typeof(List<>).MakeGenericType(collectionElementType))
The other problem that you have is that you can't just call Map<T>(childElement). First of all, T is not the right type -- it's the parent element's type, not the child's. Secondly, the child is actually a collection, and Map<T> doesn't know how to handle collections, only individual objects. We have to loop over the child elements, map onto each single one (calling Map<T> with the type of the elements in the collection -- in your example, Map<Field), and then add them all to the collection. I've made a new version of your Map<T> that works:
public T Map<T>(XElement element) where T : class, new()
{
T entity = (T)Activator.CreateInstance(typeof(T));
if (element.HasAttributes)
{
MapXMLAttributesToObject<T>(element, entity);
}
if (element.HasElements)
{
foreach (var childElement in element.Elements())
{
var property = GetProperty<T>(childElement.Name.LocalName);
// If the child element has child elements as well, we know this is a collection.
if (childElement.HasElements)
{
// Assume collections are of type IEnumerable<T> or List<T>
var collectionElementType = property.PropertyType.GetGenericArguments()[0];
// var collectionValue = new List<collectionElementType>()
var collectionValue = Activator.CreateInstance(typeof(List<>).MakeGenericType(collectionElementType));
foreach (var grandchildElement in childElement.Elements())
{
// var collectionElement = this.Map<collectionElementType>(grandchildElement);
var collectionElement = this.GetType().GetMethod("Map").MakeGenericMethod(collectionElementType).Invoke(this, new object[] { grandchildElement });
collectionValue.GetType().GetMethod("Add").Invoke(collectionValue, new object[] { collectionElement });
}
property.SetValue(entity, collectionValue, null);
}
else
{
// I'm not sure what this should do -- this case doesn't happen in your example.
throw new NotImplementedException();
}
}
}
return entity;
}
It certainly needs some more error handling, and I'm assuming you wanted to do something useful in the case where I threw a NotImplementedException. However, it works on your sample.

Categories

Resources