I've implemented the composite pattern as follows
public interface IComponent
{
string Name { get; }
}
public interface IComposite : IComponent
{
void AddRange(IEnumerable<IComponent> components);
}
public interface ILeaf : IComponent
{
string Content { get; }
string Parent { get; }
}
public class Composite : IComposite
{
// return an iterator?
private readonly List<IComponent> _children = new List<IComponent>();
public Composite(string name)
{
Name = name;
}
public string Name { get; }
public void AddRange(IEnumerable<IComponent> components)
{
_children.AddRange(components);
}
}
public class Leaf : ILeaf
{
public string Name { get; }
public string Content { get; }
public string Parent { get; }
public Leaf(string name, string content, string parent)
{
Name = name;
Content = content;
Parent = parent;
}
}
I've populated the composite from an xml file as follows
var collection = XElement.Load(#"C:\somexml.xml");
var composite = CreateComposite(collection);
where
public IComponent CreateComposite(XElement element)
{
if (!element.HasElements)
return new Leaf(element.Name.LocalName, element.Value, element.Parent.Name.LocalName);
var composite = new Composite(element.Name.LocalName);
composite.AddRange(element.Elements().Select(CreateComposite));
return composite;
}
This populates my composite as expected - great! However, I'd now like my composite to return an iterator via the implementation of IEnumerable. So I tried this
public class Composite : IComposite, IEnumerable<IComponent>
{
// return an iterator?
private readonly List<IComponent> _children = new List<IComponent>();
public Composite(string name)
{
Name = name;
}
public string Name { get; }
public void AddRange(IEnumerable<IComponent> components)
{
_children.AddRange(components);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<IComponent> GetEnumerator()
{
foreach (var child in _children)
{
yield return child;
}
}
}
But this only iterates through the top level of components, i.e., any components nested within _children are not returned. How do I update this to recursively iterate through all components?
You can iterate recursively like this (it will do iteration in depth-first manner):
public interface IComposite : IComponent, IEnumerable<IComponent>
{
void AddRange(IEnumerable<IComponent> components);
}
public IEnumerator<IComponent> GetEnumerator()
{
foreach (var child in _children)
{
yield return child;
var composite = child as IComposite;
if (composite != null) {
foreach (var sub in composite) {
yield return sub;
}
}
}
}
If you want to avoid the cast to IComposite - you need to redesign your interfaces and make your Composite to hold a list of another IComposites instead of components. Then ILeft will also become IComposite with dummy implementation.
You could implement the traversal recursively using Linq as follows.
public IEnumerable<IComponent> GetSuccessors()
{
return _children
.Concat(_children.SelectMany(iChild => iChild.GetSuccessors());
}
If depht-first traversal is desired, you can use the following implementation.
public IEnumerable<IComponent> GetSuccessors()
{
return _children
.SelectMany(iChild => new IComponent[]{iChild}.Concat(iChild.GetSuccessors()));
}
Or, if you need it using your initial syntax, you could use the following.
public IEnumerator<IComponent> GetEnumerator()
{
var Successors
= _children
.SelectMany(iChild => new IComponent[]{iChild}.Concat(iChild.GetSuccessors()));
foreach (var iSuccessor in Successors)
{
yield return iSuccessor;
}
}
Related
I want to create builder for my purpose, with such call chain:
User user = new CommonBuilder(new UserNode()).Root //generic parameter, currently is User
.Group.Group.Folder.Build();
Here is the code, which I use:
public abstract class AbstractNode
{
public Guid Id { get; } = Guid.NewGuid();
}
public abstract class AbstractNode<T> where T : AbstractNode<T>
{
}
public class CommonBuilder<T> where T : AbstractNode<T>
{
public T Root { get; private set; }
public CommonBuilder(T root)
{
Root = root;
}
}
public class UserNode : AbstractNode<UserNode>
{
private GroupNode _group;
public GroupNode Group
{
get
{
if (_group is null)
{
_group = new GroupNode();
}
return _group;
}
}
}
public class GroupNode : AbstractNode<GroupNode>
{
private GroupNode _group;
public GroupNode Group
{
get
{
if (_group is null)
{
_group = new GroupNode();
}
return _group;
}
}
private FolderNode _folder;
public FolderNode Folder
{
get
{
if (_folder is null)
{
_folder = new FolderNode();
}
return _folder;
}
}
}
public class FolderNode : AbstractNode<FolderNode>
{
}
The problem is in the Build() method, which need to return Root from CommonBuilder, not the File.
Where must I place Build() method, which must be always called at the end of a chain, which returns Root of a builder?
In case when it's required to make a chain the same object should be returned, even as another interface check first and second examples of implementation Builder with Fluent intefaces
I've tried to implement your case to fit the role, check if it will fits your requirements:
public interface IGroup<T>
{
IGroup<T> Group { get; }
IFolder<T> Folder { get; }
}
public interface IFolder<T>
{
T Build();
}
Builder implements all required interfaces. And returns itself in each call. In general you can put Build method in the builder itself and call it separately after the end of chain execution.
public class CommonBuilder<T> : IGroup<T>, IFolder<T> where T: INode, new()
{
private T _root = new T();
public T Build()
{
return _root;
}
public IGroup<T> Group
{
get
{
_root.MoveToGroup();
return this;
}
}
public IFolder<T> Folder
{
get
{
_root.MoveToFolder();
return this;
}
}
}
Because of generics it's required to set some limitations on generic parameter which is done with INode interface
public interface INode
{
void MoveToGroup();
void MoveToFolder();
}
Testing user object
public class User : INode
{
public StringBuilder Path { get; } = new StringBuilder();
public void MoveToFolder()
{
Path.AppendLine("Folder");
}
public void MoveToGroup()
{
Path.AppendLine("Group");
}
public override string ToString()
{
return Path.ToString();
}
}
And the call will looks like
var user = new CommonBuilder<User>().Group.Group.Folder.Build();
EDIT
Maybe as a the first stage it makes sence to get rid of Fluent interfaces and implement logic using just a Builder:
public class FolderNode : INode<Folder>
{
private readonly Folder _folder = new Folder();
public Folder Build()
{
return _folder;
}
public void AppendGroup()
{
_folder.Path.AppendLine("Folder Group");
}
public void AppendFolder()
{
_folder.Path.AppendLine("Folder Folder");
}
}
public class UserNode : INode<User>
{
private readonly User _user = new User();
public User Build()
{
return _user;
}
public void AppendGroup()
{
_user.Path.AppendLine("Group");
}
public void AppendFolder()
{
_user.Path.AppendLine("Folder");
}
}
public class CommonBuilder<T, TNode> where TNode : INode<T>
{
private readonly TNode _root;
public CommonBuilder(TNode root)
{
_root = root;
}
public T Build()
{
return _root.Build();
}
public CommonBuilder<T, TNode> Group {
get
{
_root.AppendGroup();
return this;
}
}
public CommonBuilder<T, TNode> Folder {
get
{
_root.AppendFolder();
return this;
}
}
}
public interface INode<out T>
{
T Build();
void AppendGroup();
void AppendFolder();
}
public class Folder
{
public StringBuilder Path { get; } = new StringBuilder();
public override string ToString()
{
return Path.ToString();
}
}
public class User
{
public StringBuilder Path { get; } = new StringBuilder();
public override string ToString()
{
return Path.ToString();
}
}
Usage:
var user = new CommonBuilder<User, UserNode>(new UserNode()).Group.Group.Folder.Build();
var folder = new CommonBuilder<Folder, FolderNode>(new FolderNode()).Group.Folder.Group.Folder.Build();
It starts out with a generic class and then I inherit from that one. Now I have a Node, which will be represented visually at a later stage. My plan was then to inherit from the Thumb control to allow my node to support dragging, but now the problem is that multiple inheritance is not supported in C#. So my only option at this point seems to be to just scrap my code and inherit the base class from Thumb (which I don't prefer due to my plan of having certain Node classes that does not support the functionality in the Thumb class). Is there no way for me to use my generic class and at the same time inherit functionality from the Thumb class (WPF)? It would be very nice to be able to inherit Node to create more specialized classes that could also support functionality from WPF controls like Thumb.
public class BaseNode<T> where T : BaseNode<T>
{
private T _item;
private T _parent;
private List<BaseNode<T>> _children;
public T Item
{
get { return _item; }
set { _item = value; }
}
public BaseNode(T item)
{
_item = item;
}
public void SetParent(T parent)
{
_parent.Item = parent;
}
public void AddChild(T child)
{
_children.Add(new BaseNode<T>(child));
}
public void RemoveChild(T child)
{
var node = _children.FirstOrDefault(e => e.Item.Equals(child));
if (node != null)
_children.Remove(node);
}
}
public class Node : BaseNode<Node>
{
private Node _item;
private List<NodeElement> NodeElements;
Node (Node item) : base(item)
{
_item = item;
}
public void ResetElements()
{
NodeElements.ForEach(e => e.ResetState());
}
public void AddElement(NodeElement element)
{
NodeElements.Add(element);
}
public void RemoveElement(NodeElement element)
{
var elem = NodeElements.FirstOrDefault(e => e.Equals(element));
if (elem != null)
NodeElements.Remove(elem);
}
}
If you want to create a custom Thumb your class should inherit from Thumb. You can then use your generic class using composition. Something like this:
public interface INode<T>
{
T Item { get; set; }
void SetParent(T parent);
void AddChild(T child);
void RemoveChild(T child);
}
public class BaseNode<T> where T : INode<T>
{
private T _item;
private T _parent;
private List<BaseNode<T>> _children;
public T Item
{
get { return _item; }
set { _item = value; }
}
public BaseNode(T item)
{
_item = item;
}
public void SetParent(T parent)
{
_parent.Item = parent;
}
public void AddChild(T child)
{
_children.Add(new BaseNode<T>(child));
}
public void RemoveChild(T child)
{
var node = _children.FirstOrDefault(e => e.Item.Equals(child));
if (node != null)
_children.Remove(node);
}
}
public class Node : Thumb, INode<Node>
{
private Node _item;
private List<NodeElement> NodeElements;
private readonly BaseNode<Node> _base;
public Node()
{
_base = new BaseNode<Node>(this);
}
public void ResetElements()
{
NodeElements.ForEach(e => e.ResetState());
}
public void AddElement(NodeElement element)
{
NodeElements.Add(element);
}
public void RemoveElement(NodeElement element)
{
var elem = NodeElements.FirstOrDefault(e => e.Equals(element));
if (elem != null)
NodeElements.Remove(elem);
}
public Node Item
{
get { return _base.Item; }
set { _base.Item = value; }
}
public void SetParent(Node parent)
{
_base.SetParent(parent);
}
public void AddChild(Node child)
{
_base.AddChild(child);
}
public void RemoveChild(Node child)
{
_base.RemoveChild(child);
}
}
All nodes inclucing the custom control implements the INode<T> interface.
I'm trying to inherit a method that returns a Generic BindingList of type ServerType. For example, let's say I have the following:
public interface IServer
{
string IpAddress { get; set; }
string Name { get; set; }
string HostName { get; set; }
string OsVersion { get; set; }
}
public class BaseServer : IServer
{
private string _IpAddress;
private string _Name;
private string _HostName;
private string _OsVersion;
public string IpAddress
{
get { return _IpAddress; }
set { _IpAddress = value; }
}
public string Name
{
get { return _Name; }
set { _Name = value; }
}
public string HostName
{
get { return _HostName; }
set { _HostName = value; }
}
public string OsVersion
{
get { return _OsVersion; }
set { _OsVersion = value; }
}
}
public class ServerTypeA : BaseServer { }
public class ServerTypeB : BaseServer { }
public class ServerTypeC : BaseServer { }
public class ServerTypeList : List<ServerTypeA>
{
public BindingList<ServerTypeA> ToBindingList()
{
BindingList<ServerTypeA> myBindingList = new BindingList<ServerTypeA>();
foreach (ServerTypeA item in this.ToList<ServerTypeA>())
{
_bl.Add(item);
}
return _bl;
}
}
Is there any way I can do the "ToBindingList" method without having to repeat it in each derived server class and have it use the correct generic type.
First offf donĀ“t derive from List<T>. Instead use it (favor composition over inheritance).
Then make your Repositories-class generic:
public class Repository : Server
{
}
public class Repositories<T> where T: Server
{
private List<T> theList = new List<T>();
public Repositories<T>(List<T> theList) this.theList = theList; }
public BindingList<T> ToBindingList()
{
BindingList<T> myBindingList = new BindingList<T>();
foreach (Titem in this.theList)
{
_bl.Add(item);
}
return _bl;
}
}
Now you can have Repositories-instances of arbitrary classes deriving from Server.
First, create a base list for all your collections:
public class MyListBase<T> : List<T>
where T: Server
{
public BindingList<T> ToBindingList()
{
BindingList<T> myBindingList = new BindingList<T>();
foreach (T item in this.ToList<T>())
myBindingList.Add(item);
return myBindingList;
}
}
Then use this one to inherit from:
public class Repositories : MyListBase<Repository>
{
}
public class ItemCollection
{
List<AbstractItem> LibCollection;
public ItemCollection()
{
LibCollection = new List<AbstractItem>();
}
public List<AbstractItem> ListForSearch()
{
return LibCollection;
}
and in another class i wrote this:
public class Logic
{
ItemCollection ITC;
List<AbstractItem> List;
public Logic()
{
ITC = new ItemCollection();
List = ITC.ListForSearch();
}
public List<AbstractItem> search(string TheBookYouLookingFor)
{
foreach (var item in List)
{
//some code..
}
and the list in the foreach is contain nothing
and i need to work on this list (this list is should be the same content as libcollection) for the search method
If ItemCollection serves no purpose other than to own the List<AbstractItem>, then the class should probably be removed altogether and just use List<AbstractItem> instead.
If ItemCollection has another purpose and others shouldn't have access to the underlying List<AbstractItem>, it can implementIEnumerable<AbstractItem>:
class ItemCollection : IEnumerable<AbstractItem>
{
List<AbstractItem> LibCollection;
public ItemCollection() {
this.LibCollection = new List<AbstractItem>();
}
IEnumerator<AbstractItem> IEnumerable<AbstractItem>.GetEnumerator() {
return this.LibCollection.GetEnumerator();
}
IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return ((IEnumerable)this.LibCollection).GetEnumerator();
}
}
class Logic
{
ItemCollection ITC;
public Logic() {
ITC = new ItemCollection();
}
public List<AbstractItem> Search(string TheBookYouLookingFor) {
foreach (var item in this.ITC) {
// Do something useful
}
return null; // Do something useful, of course
}
}
Otherwise, you may want to expose LibCollection directly and let other code enumerate over that:
class ItemCollection
{
public List<AbstractItem> LibCollection { get; private set; }
public ItemCollection() {
this.LibCollection = new List<AbstractItem>();
}
}
class Logic
{
ItemCollection ITC;
public Logic() {
ITC = new ItemCollection();
}
public List<AbstractItem> Search(string TheBookYouLookingFor) {
foreach (var item in this.ITC.LibCollection) {
// Do something useful
}
return null; // Do something useful
}
}
This is a entity and i want to list all the children node for a given node in a generic function
public static List<T> BuildTree<T>(List<T> list, T selectNode string keyPropName, string parentPropName, string levelPropName, int level = 0)
{
List<T> entity = new List<T>();
foreach (T item in list)
{
}
return entity;
}
example of the entity structure
protected long _coakey;
protected long _parentkey;
protected string _coacode;
protected string _coacodeclient;
protected string _coaname;
protected int _coalevel;
[DataMember]
public long coakey
{
get { return _coakey; }
set { _coakey = value; this.OnChnaged(); }
}
[DataMember]
public long parentkey
{
get { return _parentkey; }
set { _parentkey = value; this.OnChnaged(); }
}
[DataMember]
public string coacode
{
get { return _coacode; }
set { _coacode = value; this.OnChnaged(); }
}
[DataMember]
public string coacodeclient
{
get { return _coacodeclient; }
set { _coacodeclient = value; this.OnChnaged(); }
}
[DataMember]
public string coaname
{
get { return _coaname; }
set { _coaname = value; this.OnChnaged(); }
}
[DataMember]
public int coalevel
{
get { return _coalevel; }
set { _coalevel = value; this.OnChnaged(); }
}
Your BuildTree<T> method cannot determine the structure of the tree unless it knows something about its structure. At a very minimum, I would suggest making a base class or interface that defines a tree node, and then change the BuildTree method to work specifically with those types of objects. Then, it will be able to figure out the tree structure. Each of you entity classes would have to implement that tree node interface or inherit from the tree node base class. For instance:
public abstract class TreeNodeBase
{
public long parentkey
{
get { return _parentkey; }
set { _parentkey = value; this.OnChanged(); }
}
protected long _parentkey;
}
public class MyEntityTreeNode : TreeNodeBase
{
public long coakey
{
get { return _coakey; }
set { _coakey = value; this.OnChanged(); }
}
protected long _coakey;
// etc...
}
// Note the generic type constraint at the end of the next line
public static List<T> BuildTree<T>(List<T> list, T selectNode, string keyPropName, string parentPropName, string levelPropName, int level) where T : TreeNodeBase
{
List<T> entity = new List<T>();
foreach (TreeNodeBase node in list)
{
long parentKey = node.parentkey;
// etc...
}
return entity;
}
Node class:
public class Node<TKey, TValue> where TKey : IEquatable<TKey>
{
public TKey Key { get; set; }
public TKey ParentKey { get; set; }
public TValue Data { get; set; }
public readonly List<Node<TKey, TValue>> Children = new List<Node<TKey, TValue>>();
}
TreeBuilder:
public static Node<TKey, TValue> BuildTree<TKey, TValue>(IEnumerable<Node<TKey, TValue>> list,
Node<TKey, TValue> selectNode)
where TKey : IEquatable<TKey>
{
if (ReferenceEquals(selectNode, null))
{
return null;
}
var selectNodeKey = selectNode.Key;
foreach (var childNode in list.Where(x => x.ParentKey.Equals(selectNodeKey)))
{
selectNode.Children.Add(BuildTree(list, childNode));
}
return selectNode;
}
Usage:
List<MyClass> list = ...
var nodes = list.Select(x => new Node<long, MyClass>
{
Key = x.MyKey,
ParentKey = x.MyParentKey,
Data = x
}).ToList();
var startNode = nodes.FirstOrDefault(x => x.Data.Stuff == "Pick me!");
var tree = BuildTree(nodes, startNode);
MyClass example:
public class MyClass
{
public long MyKey;
public long MyParentKey;
public string Name;
public string Text;
public string Stuff;
}
I have solved it my self hope it help you
public static List<T> BuildTree<T>(List<T> list, T selectedNode, string keyPropName, string parentPropName, int endLevel = 0, int level = 0)
{
List<T> entity = new List<T>();
Type type = typeof(T);
PropertyInfo keyProp = type.GetProperty(keyPropName);
string _selectedNodekey = keyProp.GetValue(selectedNode, null).ToString();
PropertyInfo parentProp = type.GetProperty(parentPropName);
foreach (T item in list)
{
string _key = keyProp.GetValue(item, null).ToString();
string _parent = parentProp.GetValue(item, null).ToString();
if (_selectedNodekey == _parent)
{
T obj = (T)Activator.CreateInstance(typeof(T));
obj = item;
entity.Add(obj);
if (level == endLevel && level!=0) break;
entity.AddRange(BuildTree<T>(list, obj, keyPropName, parentPropName, level + 1));
}
}
return entity;
}