Hi I am trying to create a directory structure using composite pattern. I have an interface IAsset which is implemented by the file and folder class. So both are an Asset. Now I want to loop through all the files in all the folders but I am getting the error message:
Program.IAsset is not enumerable
This error message is in the inner foreach loop of getassetSize() method.
public class Program
{
public interface IAsset
{
double GetAssetSize();
void AddAsset(IAsset a);
}
public class File : IAsset
{
public double Size { get; set; }
public double GetAssetSize()
{
return Size;
}
public void AddAsset(IAsset a)
{
Console.WriteLine("No asset can be added to a file");
}
}
public class Folder : IAsset
{
public double Size { get { return _size; } set { _size = value; } }
private double _size = 0;
public List<IAsset> list = new List<IAsset>();
public double GetAssetSize()
{
foreach (var asset in list)
{
foreach (var x in asset)
{
// _size = x.GetAssetSize();
}
}
return _size;
}
public void AddAsset(IAsset a)
{
list.Add(a);
}
}
To fit into the composite pattern IAsset would need to inherit IEnumerable<IAsset> or provide a member which implements it. For example:
public interface IAsset : IEnumerable<IAsset>
{
double GetAssetSize();
void AddAsset(IAsset a);
}
public class File : IAsset
{
...
public IEnumerator<IAsset> GetEnumerator()
{
return new IAsset[0].GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
public class Folder : IAsset
{
...
public IEnumerator<IAsset> GetEnumerator()
{
return this.list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
Or this:
public interface IAsset
{
double GetAssetSize();
void AddAsset(IAsset a);
IEnumerable<IAsset> Assets { get; }
}
public class File : IAsset
{
...
public IEnumerator<IAsset> Assets
{
get { return new IAsset[0]; }
}
}
public class Folder : IAsset
{
...
public IEnumerator<IAsset> GetEnumerator()
{
get { return this.list; }
}
}
Assuming that you want to sum the size of the files in the directory, you have one too many loops going. This would do it...
public double GetAssetSize()
{
foreach (var asset in list)
{
_size += x.GetAssetSize();
}
return _size;
}
Related
I have a iterator pattern. But I want to make it generic. So that you can have strings and numbers. Because now you only can put strings in the list items.
So I have this:
public interface IIterator< out T>
{
void First();
T Next();
bool IsDone();
T CurrentItem();
}
public interface IAggregate< out T>
{
IIterator <T> CreateIterator();
}
}
public class Science : IAggregate<T>
{
private LinkedList<string> Subjects;
public Science()
{
Subjects = new LinkedList<string>();
Subjects.AddFirst("Maths");
Subjects.AddFirst("Comp. Sc.");
Subjects.AddFirst(99);// So this of course fails
}
public IIterator<T> CreateIterator()
{
return new ScienceIterator<T>(Subjects);
}
}
public class ScienceIterator : IIterator
{
private System.Collections.Generic.LinkedList<string> Subjects;
private int position;
public ScienceIterator(LinkedList<string> subjects)
{
this.Subjects = subjects;
position = 0;
}
public void First()
{
position = 0;
}
public string Next()
{
return Subjects.ElementAt(position++);
}
public bool IsDone()
{
if (position < Subjects.Count)
{
return false;
}
else
{
return true;
}
}
public string CurrentItem()
{
return Subjects.ElementAt(position);
}
}
So my question is, is this possible in the default C# collection? Or you have to make your own LinkedList?
Thank you
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();
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;
}
}
This question already has answers here:
IEnumerable , IEnumerator vs foreach, when to use what [duplicate]
(3 answers)
Closed 6 years ago.
I have a simple class, Employee, and another class, Company, which contains an array of employees. The company class has 2 nested classes with iterators. One orders the items from first to last, and the second one reverses the order. The NormalEnumeration is the default. When I attempt to use ReverseOrder" in a foreach loop, I get this error:
foreach statement cannot operate on variables of type
'Zadanie_1.Company.ReverseEnumeration' because
'Zadanie_1.Company.ReverseEnumeration' does not contain a public
definition for 'GetEnumerator'
My questions is: How can I implement the custom iterators?
public class Employee
{
private string surname, position;
public string Stanowisko { get { return position; } }
public Employee (string nazwisko, string stanowisko)
{
this.surname = nazwisko;
this.position = stanowisko;
}
public override string ToString()
{
return string.Format("nazwisko: {0}, stanowisko: {1}", surname, position);
}
}
public class Company:IEnumerable
{
string name;
private Employee[] employeeArray;
public Company(string nazwa, Employee[] pracownicy)
{
this.name = nazwa;
this.employeeArray = pracownicy;
}
public IEnumerator GetEnumerator()
{
//foreach (Pracownik item in pracownicy)
//{
// yield return item;
//}
return new NormalEnumeration(this);
}
public IEnumerator Ordered()
{
return new NormalEnumeration(this);
}
public override string ToString()
{
return string.Format("Nazwa firmy: {0}, liczba pracowników: {1}", name, employeeArray.Length);
}
public class ReverseEnumeration : IEnumerator
{
Company f;
int counter;
public ReverseEnumeration(Company f)
{
this.f = f;
counter = f.employeeArray.Length;
}
public object Current
{
get
{
Console.WriteLine("Current");
return f.employeeArray[counter];
}
}
public bool MoveNext()
{
if (counter > 0)
{
Console.WriteLine("Move next:");
counter--;
return true;
}
else
return false;
}
public void Reset()
{
counter = f.employeeArray.Length;
}
}
public class NormalEnumeration : IEnumerator
{
Company f;
int counter = -1;
public NormalEnumeration(Company f)
{
this.f = f;
}
public object Current
{
get
{
Console.WriteLine("Current");
return f.employeeArray[counter];
}
}
public bool MoveNext()
{
if (counter >= f.employeeArray.Length-1)
return false;
else
{
counter++;
return true;
}
}
public void Reset()
{
counter = -1;
}
}
}
Comment under the question:
I tried to call the reverse iterator this way:
foreach (Employee item in new Company.ReverseEnumeration(instancenamehere)) {
Console.WriteLine(item);
}
For this to work, ReverseEnumration would have to implement IEnumerable. If you want to be able to modify the enumerator, just add a new property to the Company class.
public class Company : IEnumerable
{
public IEnumerator Enumerator { get; set; }
public IEnumerator GetEnumerator()
{
return Enumerator;
}
// other members
}
You can set the default enumerator in the constructor.
public Company(string nazwa, Employee[] pracownicy)
{
Enumerator = new NormalEnumeration(this);
// other stuff
}
You should extract your enumerators out of the Company class, because they don't use it's internals anyway. This will enable you to easily change enumerators from the outside.
var c = new Company(null, null);
c.Enumerator = new ReverseEnumeration(c);
I have an assignment to implement a linear linked list using generics in C# console application.
The class should also contain a print() method to print the elements of the list.
Conditions for Linear List are to be as a long type (CNodeLong) or String Type (CNodeString), both inherited from CNode with virtual function Print().
I have a problem implementing the printing method. I don't know where should it stand, and how to override it.
Here is my CNode class and CList class:
public class CNode<T>
{
private CNode<T> next;
private T item;
public CNode<T> Next
{
get { return next; }
set { next = value; }
}
public T Item
{
get { return item; }
set { item = value; }
}
public CNode(T item)
: this(item,null)
{
}
public CNode(T item, CNode<T> next)
{
this.item = item;
this.next = next;
}
}
class CList<T>
{
private CNode<T> first;
private CNode<T> last;
private int count;
public CNode<T> First
{
get { return first; }
}
public CNode<T> Last
{
get { return last; }
}
public int Count
{
get { return count; }
}
public CList(string strListName)
{
count = 0;
first = last = null;
}
}
You probably should override ToString method and add the virtual Print method to CNode.
(I've also added the PrintList method to CList):
public class CNode<T>
{
...
public override string ToString()
{
return item.ToString();
}
virtual public void Print()
{
Console.WriteLine(item);
}
}
class CList<T>
{
...
public void PrintList()
{
CNode<T> current = first;
while (current != null)
{
Console.WriteLine(current.ToString());
current = current.Next;
}
}
}
Then you can override the virtual method in the child classes:
public class CNodeString : CNode<string>
{
public CNodeString(string item) : base(item) { }
override public void Print()
{
Console.WriteLine("Printing from CNodeString");
base.Print();
}
}
public class CNodeLong : CNode<long>
{
public CNodeLong(long item) : base(item) { }
override public void Print()
{
Console.WriteLine("Printing from CNodeLong");
base.Print();
}
}