Controlling access to an internal collection in c# - Pattern required - c#

This is kind of hard to explain, I hope my English is sufficient:
I have a class "A" which should maintain a list of objects of class "B" (like a private List). A consumer of class "A" should be able to add items to the list. After the items are added to the list, the consumer should not be able to modify them again, left alone that he should not be able to temper with the list itself (add or remove items). But he should be able to enumerate the items in the list and get their values. Is there a pattern for it? How would you do that?
If the question is not clear enough, please let me know.

To prevent editing the list or its items you have to make them immutable, which means you have to return a new instance of an element on every request.
See Eric Lippert's excellent series of "Immutability in C#": http://blogs.msdn.com/ericlippert/archive/tags/Immutability/C_2300_/default.aspx (you have to scroll down a bit)

As many of these answers show, there are many ways to make the collection itself immutable.
It takes more effort to keep the members of the collection immutable. One possibility is to use a facade/proxy (sorry for the lack of brevity):
class B
{
public B(int data)
{
this.data = data;
}
public int data
{
get { return privateData; }
set { privateData = value; }
}
private int privateData;
}
class ProxyB
{
public ProxyB(B b)
{
actual = b;
}
public int data
{
get { return actual.data; }
}
private B actual;
}
class A : IEnumerable<ProxyB>
{
private List<B> bList = new List<B>();
class ProxyEnumerator : IEnumerator<ProxyB>
{
private IEnumerator<B> b_enum;
public ProxyEnumerator(IEnumerator<B> benum)
{
b_enum = benum;
}
public bool MoveNext()
{
return b_enum.MoveNext();
}
public ProxyB Current
{
get { return new ProxyB(b_enum.Current); }
}
Object IEnumerator.Current
{
get { return this.Current; }
}
public void Reset()
{
b_enum.Reset();
}
public void Dispose()
{
b_enum.Dispose();
}
}
public void AddB(B b) { bList.Add(b); }
public IEnumerator<ProxyB> GetEnumerator()
{
return new ProxyEnumerator(bList.GetEnumerator());
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
The downside of this solution is that the caller will be iterating over a collection of ProxyB objects, rather than the B objects they added.

EDIT: Added support for edition contexts. Caller can only add elements inside an edition context. You can aditionally enforce that only one edition context can be created for the lifetime of the instance.
Using encapsulation you can define any set of policies to access the inner private member. The following example is a basic implementation of your requirements:
namespace ConsoleApplication2
{
using System;
using System.Collections.Generic;
using System.Collections;
class B
{
}
interface IEditable
{
void StartEdit();
void StopEdit();
}
class EditContext<T> : IDisposable where T : IEditable
{
private T parent;
public EditContext(T parent)
{
parent.StartEdit();
this.parent = parent;
}
public void Dispose()
{
this.parent.StopEdit();
}
}
class A : IEnumerable<B>, IEditable
{
private List<B> _myList = new List<B>();
private bool editable;
public void Add(B o)
{
if (!editable)
{
throw new NotSupportedException();
}
_myList.Add(o);
}
public EditContext<A> ForEdition()
{
return new EditContext<A>(this);
}
public IEnumerator<B> GetEnumerator()
{
return _myList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
public void StartEdit()
{
this.editable = true;
}
public void StopEdit()
{
this.editable = false;
}
}
class Program
{
static void Main(string[] args)
{
A a = new A();
using (EditContext<A> edit = a.ForEdition())
{
a.Add(new B());
a.Add(new B());
}
foreach (B o in a)
{
Console.WriteLine(o.GetType().ToString());
}
a.Add(new B());
Console.ReadLine();
}
}
}

You basically want to avoid to give away references to the class B items. That's why you should do a copy of the items.
I think this can be solved with the ToArray() method of a List object. You need to create a deep-copy of the list if you want to prevent changes.
Generally speaking: most of the times it is not worthwhile to do a copy to enforce good behaviour, especially when you also write the consumer.

public class MyList<T> : IEnumerable<T>{
public MyList(IEnumerable<T> source){
data.AddRange(source);
}
public IEnumerator<T> GetEnumerator(){
return data.Enumerator();
}
private List<T> data = new List<T>();
}
The downside is that a consumer can modify the items it gets from the Enumerator, a solution is to make deepcopy of the private List<T>.

It wasn't clear whether you also needed the B instances themselves to be immutable once added to the list. You can play a trick here by using a read-only interface for B, and only exposing these through the list.
internal class B : IB
{
private string someData;
public string SomeData
{
get { return someData; }
set { someData = value; }
}
}
public interface IB
{
string SomeData { get; }
}

The simplest that I can think of is return a readonly version of the underlying collection if editing is no longer allowed.
public IList ListOfB
{
get
{
if (_readOnlyMode)
return listOfB.AsReadOnly(); // also use ArrayList.ReadOnly(listOfB);
else
return listOfB;
}
}
Personally though, I would not expose the underlying list to the client and just provide methods for adding, removing, and enumerating the B instances.

Wow, there are some overly complex answers here for a simple problem.
Have a private List<T>
Have an public void AddItem(T item) method - whenever you decide to make that stop working, make it stop working. You could throw an exception or you could just make it fail silently. Depends on what you got going on over there.
Have a public T[] GetItems() method that does return _theList.ToArray()

Related

How can I access private members from other classes?

I'm not that new to C# but don't have as much experience as in Java.
As you know, in Java, we can access all the private members from outer classes.
So I tried the same thing in C# because I had some fields and methods needed to be accessed from only inside my plugin library and didn't want it to be shown to users. A simple example can be like this.
public static class StaticClass {
public class InstanceClass {
private int oldValue;
public int Value;
}
public static void Backup(InstanceClass ic) {
ic.oldValue = ic.Value;
}
public static void Restore(InstanceClass ic) {
ic.Value = ic.oldValue;
}
}
If I make the field oldValue public, then it'll be mess and look dirty when end users use the plugin. It doesn't have to be an Inner class or in a some specific form. I just want to know if there is any way to control or access private members of an instance from other static classes in the same assembly only by me.
For allowing access only within assembly use internal modifier.
public class InstanceClass {
internal int oldValue;
public int Value;
}
This is not possible in C#. The container class has no special access over the nested class.
You can access private members of the container from the nested class, but not vice versa. The pattern you're trying to use simply isn't used in C# - it's a violation of member accessibility. There are some hacks to force the Java pattern on C# (using reflection or abusing interfaces), but they are just that - hacks.
The "cleanest" approach might look something like this:
public static class StaticClass
{
private interface IInstanceClassInternal
{
int OldValue { get; set; }
}
public sealed class InstanceClass : IInstanceClassInternal
{
int IInstanceClassInternal.OldValue { get; set; }
public int Value;
}
public static void Backup(InstanceClass ic)
{
((IInstanceClassInternal)ic).OldValue = ic.Value;
}
public static void Restore(InstanceClass ic)
{
ic.Value = ((IInstanceClassInternal)ic).OldValue;
}
}
It's obvious that you're trying to write Java in C# - the patterns, the coding style... That's probably a bad idea. Those static methods should probably be extension methods. The "hidden functionality in an object" doesn't quite sit with C#'s notion of OOP - your parent shouldn't have free access to your guts, it should only really have the same public interface everyone else has. After all, that's the whole point of LSP - such tight coupling is quite tricky for any extensibility. Why separate StaticClass from InstanceClass in the first place, if you want StaticClass to mess with InstanceClasses privates? Just make Backup and Restore public members of InstanceClass - or even a part of an interface (perhaps even through explicit implementation, if you want to "hide" it from users of InstanceClass).
You can use the internal access modifier, see https://msdn.microsoft.com/en-us/library/ms173121.aspx
Internal is only visible from inside the assembly
Example: https://dotnetfiddle.net/FNavfE
Have you tried to make it "internal"? It will be available in same dll but not external dll.
public class InstanceClass {
internal int oldValue;
public int Value;
}
Technically, you can use Reflection (if you insist on private field and a static class methods):
using System.Reflection;
...
public static void Backup(InstanceClass ic) {
if (null == ic)
throw new ArgumentNullException("ic");
ic.GetType()
.GetField("oldValue", BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(ic, ic.Value);
}
public static void Restore(InstanceClass ic) {
if (null == ic)
throw new ArgumentNullException("ic");
ic.Value = (int) (ic.GetType()
.GetField("oldValue", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(ic));
}
however, a much better approach is to change access modifier from private to internal:
public class InstanceClass {
internal int oldValue;
public int Value;
}
Even better solution is to move both Backup and Restore methods into InstanceClass:
public class InstanceClass {
private int oldValue;
public int Value;
public void Backup() {
oldValue = Value;
}
public void Restore() {
Value = oldValue;
}
}
This field oldValue is an implementation detail of both StaticClass and InstanceClass. Lets make InstanceClass an implementation detail of StaticClass and export an interface StaticClass.IInstance to external clients:
public static class StaticClass {
public interface IInstance {
int Value { get; set; }
}
private class InstanceClass: IInstance {
public int oldValue;
public Value { get; set; }
}
// Static class becomes responsible for handing out `IInstance` objects
public static IInstance GetInstance() {
return new InstanceClass();
}
public static void Backup(IInstance i) {
if (i is InstanceClass ic) {
ic.oldValue = ic.Value;
}
else {
throw new InvallidOperationException("Can only Backup IInstance objects that were created by GetInstance");
}
}
public static void Restore(IInstance i) {
if (I is InstanceClass ic)
{
ic.Value = ic.oldValue;
}
else {
throw new InvallidOperationException("Can only Restore IInstance objects that were created by GetInstance");
}
}
This solution is similar to the one Luaan proposes. But instead of using an interface to export private data, it uses an interface to limit the publicly available data; to my opinion this is a cleaner design with less surprises.
It does change Value from a field to a property; so when you really need a field, this pattern does not work.
The static class in the example of OP makes it a bit awkward and having better solutions, but imagine this in a regular class, perhaps in a repository. Working on a repository, where observers should be notified when properties of items in the repository are set and not wanting the items to contain a reference to the repository or to the repositories observers, led me to searching for "method only accessible to container class?" which led me to this question.
I intend to solve it as follows:
public class Repo
{
public interface IItem
{
int Id { get; }
string MyProperty { get; }
}
private class Item
{
public int Id { get; }
public string MyProperty { get; private set; }
public bool TrySetMyProperty(string newValue)
{
if (!Equals(MyProperty, newValue) &&
IsPreconditionValid())
{
MyProperty = newValue;
return true;
}
else
{
return false;
}
IsPreconditionValid() => true;
}
}
public event EventHandler<EventArgs> OnChanged;
private readonly ConcurrentDictionary<int, Item> items = new ConcurrentDictionary<int, Item>();
public IItem GetOrCreateItemById(int id)
{
bool changed = false;
IItem result = items.GetOrAdd(int, CreateItem);
if (changed)
{
OnChanged?.Invoke(this, EventArgs.Empty);
}
return result;
IItem CreateItem(int key)
{
changed = true;
return new Item() { Id = key };
}
}
public bool TrySetItemMyProperty(int id, string newValue)
{
if (items.TryGet(id, out Item i))
{
if (i.TrySetMyProperty(newValue))
{
OnChanged?.Invoke(this, EventArgs.Empty);
return true;
}
}
return false;
}
}

interconnected lists C#

I have class with two properties which are Lists, one of it contents int - that's IDs of objects from second List. I override setters and getters to save them agreeable with each other. But when I add some this to list they are not synchronized. How to make them synchronized?
Here is code
public class Item
{
private List<Operation> _operations = new List<Operation>();
private List<int> _operationsID = new List<int>();
public List<Operation> operations
{
get { return this._operations; }
set
{
this._operations = value;
if (value != null)
{
foreach (Operation oper in value)
{
this._operationsID.Add(oper.ID);
}
}
}
}
public List<int> operationsID
{
get { return this._operationsID; }
set
{
this._operationsID = value;
if (value != null)
{
foreach (int operID in value)
{
this._operations.Add(new Operation(operID));
}
}
}
}
}
Should I override List.Add if so, how it can me made?
It is a bit unclear what it is you are trying to do, but basically it seems like you need to encapsulate those lists so the user can't work on them directly (and get them out of sync). You do this by not exposing the lists to the user. Basically you are trying to keep the items contained to the user so whenever they work on your set of items, they would be forced to go through this class and the functions that class exposes. Your only issue then is to find out what to expose to the user and in what manner.
public class Item {
private List<Operation> _operations = new List<Operation>();
private List<int> _operationsID = new List<int>();
public void addOperation(Operation o) {
_operations.Add(o);
_operationsID.Add(getIdentifier(o));
}
public void removeOperation(Operation o) {
_operations.Remove(o);
_operationsID.Remove(getIdentifier(o));
}
public void clear() {
_operations.clear();
_operationsID.clear();
}
public void findOperationMatching(Foobar foo) {
//
}
private int getIdentifier(Operation id) {
//
}
}
You have to clear previous list content before calling Add method:
public List<Operation> operations
{
get { return this._operations; }
set
{
this._operations = value;
if (value != null)
{
this._operationsID.Clear();
foreach (Operation oper in value)
{
this._operationsID.Add(oper.ID);
}
}
else
{
this._operationsID = null;
}
}
}
But to be honest, I don't think it's a good idea to keep these things in two different lists. Why don't you use Dictionary<int, Operation>?
It's a bad idea to try to manage two versions of the truth. If it were me, I'd expose one List<Operation> that callers can Add/Remove, and a second IEnumerable<int> which simply exposes the ID's of the operations:
public List<Operation> Operations { get; set; }
public IEnumerable<int> OperationIDs
{
get
{
return Operations.Select(op => op.OperationID);
}
}
This way, callers can use the Operations list to do whatever they need to do (Add, Remove, Count, etc). The OperationIDs is now not a second property that people can work with; instead it only reflects information that is in the Operations property.

C# Controlling access to an array property element

I would like to bring access to an internal array with a Property, but controlling the access to array elements.
I have write a simple example that can explain my problem better than myself.
In the example, I provide a 'Fail' class and a 'Controlled' class. The second one runs as I would like, but the approach is a bit different and it is usefull only with one array.
My question is the next:
What about if I must to have two different arrays and therefore two differenct properties.
How to do it ?
Thanks.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("The Fail Class:");
MyFailClass MyFailTestClass = new MyFailClass(5);
MyFailTestClass.MyList[2] = 11;
if (MyFailTestClass.Modified) {
Console.WriteLine("Right");
} else {
Console.WriteLine("Error");
}
Console.WriteLine("The Controlled Class:");
MyControlledClass MyControlledTestClass = new MyControlledClass(5);
MyControlledTestClass[2] = 11;
if (MyControlledTestClass.Modified) {
Console.WriteLine("Right");
} else {
Console.WriteLine("Error");
}
Console.ReadKey();
}
}
public class MyFailClass
{
// Property
public byte[] MyList
{
get
{
return myList;
}
set // <--------- Never enters here if I set a concrete array element
{
Modified = !myList.Equals(value);
myList = value;
}
}
public bool Modified { get; set; }
// Constructor
public MyFailClass(int elements)
{
myList = new byte[elements];
}
private byte[] myList;
}
public class MyControlledClass
{
// Property
public byte this[int index]
{
get
{
return myList[index];
}
set
{
Modified = !myList[index].Equals(value);
myList[index] = value;
}
}
public bool Modified { get; set; }
// Constructor
public MyControlledClass(int elements)
{
myList = new byte[elements];
}
private byte[] myList;
}
}
You might consider replacing your array property by, say, an ObservableCollection<T>.
You would probably expose the property as IList<T> since the fact that it's observable is an internal implementation detail.
public class MyClass
{
public IList<byte> MyList
{
get { return _myList; }
}
private IList<byte> _myList = new ObservableCollection<byte>();
...
}
The implementation of MyClass should handle _myList's PropertyChanged and CollectionChanged events.
Note you don't generally need a setter for a collection property - if the caller wants to replace the list he can call:
myClass.MyList.Clear();
then add new elements.
If you want two arrays, it stands to reason that you might later want three, or four (I don't know for sure, but that seems to be how things go).
In this case, I would consider making a class that's an aggregate of your "MyControlledClass"
public class IndexedClass
{
// Property
public byte this[int index]
{
get
{
return myList[index];
}
set
{
Modified = !myList[index].Equals(value);
myList[index] = value;
}
}
}
public class IndexedClassGroup
{
// Property
public IndexedClass this[int index]
{
get
{
return myList[index];
}
set
{
Modified = !myList[index].Equals(value);
myList[index] = value;
}
}
}
Then, you could access these things like a two dimensional array.
Personally, I'm a little leery of exposing an array as a gettable/settable concept, in theory, so I don't know a whole lot about the ins and outs of doing that. Whether a classes uses an array or a list or whatever seems like a private implementation detail rather than a public property. If you're going to expose something, expose an ICollection<> or IEnumerable<> and resolve it internally to an array. My two cents, anyway.

Private inheritance in C#?

I'm new to C# and wondered if there is something like private inheritance in C# (like in C++) ?
My problem is as follows:
I want to implement a queue (name it SpecialQueue) with the following changes:
The queue has a maximum number of items that can be stored in it.
If the queue is full and you insert a new item, one item will be automatically poped out of the queue (the first item in the queue) and the new item will be inserted to the end of the queue.
Some methods (such as peek()) provided by queue should not be exposed to SpecialQueue's users.
In c++ I would private ihnerit from queue, expose only the methods I want to and change others to my will. But unfortunatley, all methods in queue don't have the "Override" modifier and I don't know how to achieve that in C#.
Any help?
Regards,
Dan
Use composition: include a usual Queue as a field in your SpecialQueue. Private inheritance is actually something very similar to composition.
See http://www.parashift.com/c++-faq-lite/private-inheritance.html#faq-24.3 for discussion.
Implementation could be something like that:
public class SpecialQueue<T>
{
private int capacity;
private Queue<T> storage;
public SpecialQueue(int capacity)
{
this.capacity = capacity;
storage = new Queue<T>();
// if (capacity <= 0) throw something
}
public void Push(T value)
{
if (storage.Count == capacity)
storage.Dequeue();
storage.Enqueue(value);
}
public T Pop()
{
if (storage.Count == 0)
throw new SomeException("Queue is empty");
return storage.Dequeue();
}
public int Count
{
get { return storage.Count; }
}
}
You need to add more functions/interfaces if you want SpecialQueue to support them. I would however not recommend to implement IEnumerable, because this would allow Peek (which you want to prohibit).
You could implement the same interfaces as a Queue (or Queue<T>), have a Queue as a backing field and expose those methods that you need to, which will simply wrap the calls to the backing field.
For example (have kept implementation of ICollection in line with Queue<T>)
public class SpecialQueue<T> : IEnumerable<T>, ICollection
{
private readonly Queue<T> _queue;
#region Constructors
public SpecialQueue()
{
_queue = new Queue<T>();
}
public SpecialQueue(int capacity)
{
_queue = new Queue<T>(capacity);
}
public SpecialQueue(IEnumerable<T> collection)
{
_queue = new Queue<T>(collection);
}
#endregion
#region Methods
// implement any methods that you want public here...
#endregion
#region Interface Implementations
public IEnumerator<T> GetEnumerator()
{
return _queue.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _queue.GetEnumerator();
}
public void CopyTo(Array array, int index)
{
((ICollection) _queue).CopyTo(array, index);
}
public int Count
{
get { return _queue.Count; }
}
public object SyncRoot
{
get { return ((ICollection) _queue).SyncRoot; }
}
public bool IsSynchronized
{
get { return ((ICollection) _queue).IsSynchronized; }
}
#endregion
}

c# recursive generics data structure searching

been struggling with this for a couple of days now and still stumped.
i have a data structure that starts with containers that can hold other containers, and eventually leaf nodes. i'm looking for a way of being to iterate thru elements of a type directly, without pulling them into another collection so i can operate on them in place and then save the resulting structure out.
The code below is a noddy version, and if you set a break point on each findElements function you'll see that it drops out without recursing. this is on mono and ms runtimes, so i'm sure it's me not getting something rather than a bug ;)
also, the function should ideally be
IEnumerable<object> findElements<T>();
but i can't get the cast to work on this line then :
if (this is T) yield return this;
should ideally be
if (this is T) yield return (T)this;
thanks for any suggestions / clarity / light
using System;
using System.Collections.Generic;
using System.Text;
namespace covariantTest {
class MainClass {
public static void Main(string[] args) {
Console.WriteLine("Starting");
Document root = new Document("rooty");
root.Children.Add(new File("file 1"));
root.Children.Add(new File("file 2"));
Document doc2 = new Document("doc2");
File file3 = new File("file 3");
file3.Lines.Add(new Line("line 1 file 3"));
file3.Lines.Add(new Line("line 2 file 3"));
doc2.Children.Add(file3);
File file4 = new File("file 4");
file4.Lines.Add(new Line("stuff about stuff"));
file4.Lines.Add(new Line("Babylon n ting"));
file4.Lines.Add(new Line("last line"));
doc2.Children.Add(file4);
root.Children.Add(doc2);
// find the lines
foreach (object obj in root.findElements<Line>()) {
Line line = obj as Line;
Console.WriteLine(line.Contents);
}
// done
Console.WriteLine("Press enter to finish");
Console.ReadLine();
}
}// Main
#region classes
public class Line : ISearchable {
private string _contents = string.Empty;
public Line() {}
public Line(string contents) {
_contents = contents;
}
#region properties
public string Contents {
get { return _contents; }
set { _contents = value; }
}
#endregion properties
public IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
}
}// Line
public class File : Container {
private List<Line> _lines = new List<Line>();
public File() : base() {}
public File(string name) : base(name) {}
#region properties
public List<Line> Lines {
get { return _lines; }
set { _lines = value; }
}
#endregion properties
public override IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
else base.findElements<T>();
}
}// File
public class Document : Container {
public Document() : base() {}
public Document(string name) : base(name) {}
public override IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
else base.findElements<T>();
}
}// Document
public abstract class Container : ISearchable {
private string _name = string.Empty;
private List<Container> _children = new List<Container>();
public Container() {}
public Container(string name) {
_name = name;
}
#region properties
public string Name {
get { return _name; }
set { _name = value; }
}
public List<Container> Children {
get { return _children; }
set { _children = value; }
}
#endregion properties
#region interfaces
public virtual IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
foreach (Container item in _children) {
item.findElements<T>();
}
}
#endregion interfaces
}// Container
#endregion classes
#region interfaces
public interface ISearchable {
IEnumerable<object> findElements<T>();
}
#endregion interfaces
}// namespace
I think you code is a bit complex, but I may have bad understood you target.
Anyway, here is a sample to scan in a "flat-fashion" your tree. I also used a very small code just to show-how, but obviously you have to work on.
namespace ConsoleApplication3
{
//this is a node of your tree, but you may add whatever you want inside
class Item
{
public List<Item> Items { get; set; }
}
class Program
{
static void Main(string[] args)
{
//define the tree structure
var tree = new Item();
// (complete your tree-structrure)
//define the action delegate
Action<Item> action = (item) => Console.WriteLine(item);
//scan the hierarchy
Scan(
tree,
typeof(Item),
action);
}
//here is the flat-scan function, the "typeToFind" here is just
//for example and have very little sense to be in
static void Scan(
Item startItem,
Type typeToFind,
Action<Item> action)
{
var temp = new List<Item>();
temp.Add(startItem);
while (temp.Count > 0)
{
var item = temp[0];
temp.RemoveAt(0);
if (typeToFind.IsInstanceOfType(item))
{
action(item);
}
temp.AddRange(item.Items);
}
}
}
}
Hope this helps. Cheers.
How do you expect it to work? If I understand it correctly, then yield does not work when called from another function (so if you call base.findElements then you ain't gonna get any results from it). I suggest rewriting it without yield. To avoid creating many lists, I would pass list as a parameter, in such a way:
public interface ISearchable {
void doFindElements<T>(List<T> putThemHere);
}
// this is extender for syntactical sugar
public static class SearchableExtender
{
public static IEnumerable<T> findElements<T>(this ISearchable obj)
{
List<T> result = new List<T>();
obj.doFindElements(result);
return result;
}
}
public abstract class Container : ISearchable {
...
public virtual void doFindElements<T>(List<T> putThemHere)
{
if (this is T) putThemHere.Add(this);
foreach (Container item in _children) { item.doFindElements(putThemHere); }
}
...
}
By the way, you don't need to override doFindElements in Document, inherited version from Container will do OK, as "this" would mean a Document here. Implementation of File is completely wrong. Base Container class would not see Lines property and instead would use empty Children property. There are two ways to work around this:
You need to kill _lines and instead work with _children from the base class (for example, you can make Collection<Line> descendent that would be a wrapper around _children class by overriding InsertItem, SetItem, RemoveItem and ClearItems and calling appropriate methods of _children).
Remove _children from Container, instead make virtual abstract function IEnumerable GetChildElements() that each descendent would implement and return its own List<> of child elements. In doFindElements you would call that function instead of _children. You can even make second base class, like UntypedContainer: Container that would declare List<Container> _children, override GetChildElements() to return _children and inherit Document from it. File would still be inherited from simple Container, as it have its own children list.
The second way is simpler and better.

Categories