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();
}
}
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'm trying to create a custom control which has a collection of items, but nothing appears on design-time even if I rebuild the project.
(Parents) is custom control
How can I make it appear in the collection editor without losing it after rebuilding the project.
public class ItemsTest : UserControl
{
Parents parent;
ObjectCollections itm ;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ObjectCollections Items { get { return itm; } }
public ItemsTest ()
{
SetStyle(ControlStyles.SupportsTransparentBackColor, true);
itm = new ObjectCollections(this);
parent = new Parents();
}
}
public class ObjectCollections : CollectionBase
{
private List<Parents> _contents;
private ItemsTest itemstest = null;
public ObjectCollections(ItemsTest owner)
{
_contents = new List<Parents>();
this.itemstest = owner;
}
public int IndexOf(Parents item)
{
return _contents.IndexOf(item);
}
public void Insert(int index, Parents item)
{
_contents.Insert(index, item);
}
public void RemoveAt(int index)
{
_contents.RemoveAt(index);
}
public Parents this[int index]
{
get
{
return _contents[index];
}
set
{
_contents[index] = value;
}
}
public void Add(Parents item)
{
_contents.Add(item);
this.itemstest.Controls.Add(item);
this.itemstest.Invalidate();
}
public void Clear()
{
_contents.Clear();
}
public bool Contains(Parents item)
{
if (_contents.Contains(item))
return true;
return false;
}
public void CopyTo(Parents[] array, int arrayIndex)
{
for (int _oj = 0; _oj < Count; _oj++)
{
array.SetValue(_contents[_oj], arrayIndex++);
}
}
public int Count
{
get { return _contents.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(Parents item)
{
return _contents.Remove(item);
}
IEnumerator<Parents> IEnumerable<Parents>.GetEnumerator()
{
//some code
}
IEnumerator IEnumerable.GetEnumerator()
{
//some code
}
}
When I try to add items into the collection editor, rebuild the project, and reopen the collection editor nothing is shown in it.
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();
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);
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;
}