Custom (derived) List<T> - c#

Feel free to load your guns and take aim, but I want to understand why you shouldn't do this.
I have created a custom class designed to replace any instances of List (which I use to update XML objects behind them):
public class ListwAddRemove<T> : List<T> {
public event EventHandler<ListModifyEventArgs> OnAdd;
public event EventHandler<ListModifyEventArgs> OnRemove;
new public void Add(T o) {
base.Add(o);
if (OnAdd != null) {
OnAdd(this, new ListModifyEventArgs(o));
}
}
new public void Remove(T o) {
base.Remove(o);
if (OnRemove != null) {
OnRemove(this, new ListModifyEventArgs(o));
}
}
}
The idea is whenever I add or remove an item from this list my bound events will fire and I can deal with the XML behind automatically.
This works like a charm, so far so good.
But how do I handle a conversion between object.ToList() and my derived version?
A lot of people are saying you should derive from Collection instead... why?

You should derive from Collection<T> because it's designed to allow you to override InsertItem, and RemoveItem to add custom behavior such as what you're doing (also SetItem, to add custom behavior when changing an existing item).
It can therefore be used as an IList<T>, and any insertion/removal will automatically use the customisation.
In your case, anyone who casts to IList<T> or the base class List<T> will bypass your custom Add/Remove functionality.
Collection<T> also provides a constructor to wrap an existing list. You can expose this from your derived class to wrap a list generated by Enumerable<T>.ToList().
UPDATE
Whats the syntax to expose the constructor please?
Very simple:
public class ListwAddRemove<T> : Collection<T>
{
public ListwAddRemove<T>()
{
}
public ListwAddRemove<T>(IList<T> list) : base(list)
{
}
... implementation of overrides for InsertItem, SetItem, RemoveItem ...
}
Then use it as follows:
IList<SomeType> list = ....ToList();
ListwAddRemove<SomeType> myList = new ListwAddRemove<SomeType>(list);

For one,
void DoSomeAddingToList(List<int> list) {
list.Add(1);
}
var list = new ListwAddRemove<int>();
DoSomeAddingToList(list);
will not trigger the events. That might lead to strange effect, especially if you're not the only one using the class.
List<T> defines a very specific behaviour for Add and Remove (since it's a concrete class), and users might rely on exactly this behaviour.
I think this is generally true for using a new modifier, so this language feature should be used with caution, especially on public methods.
As others have mentioned, implementing IList<T> (using delegation/aggregation) is probably the better choice.

Related

Is a public readonly List<T> bad design?

I am currently writing an application that builds a connection to some sort of Service, gets Data in the form of a few DataTable objects and then is supposed to show it to the user.
In order to store the Data I get I made a class called DataStorage which has a List<DataTable>. Other classes need to be able to edit this List, for example adding objects that are needed or removing them if the user finds them unnecessary. I also have to be able to clear it, should I need a completely new set of data.
I could give the DataStorage methods for that but since the List<T> already offers these, I see no point in encapsulating it like that. So I made it readonly to ensure nobody tries to assign a new object - or even worse, null - and made the access modifier public.
Is this sort of design acceptable or should I always protect fields from direct access, no matter what?
General speaking you should allways take the most general type to reduce any tight coupling and to provide only those members you actually need access to. Having said this in some situations it might be better to use an ICollection instead which provides access to basic methods such as Add, Remove and Clear.
However making the collection readonly or even better a Get-only property is probably a good idea and nothing can be said against this.
We should be very careful with public which means public - whatever.
Do you let any class behave in such a way?
public class Offender {
...
public void Offend(YourClass value) {
...
// In the middle of my routine I've ruined your class
value.Data.Clear();
value.Data.Add(someStuff);
...
}
}
I suggest restricting full access to Data to trusted classes only:
public class YourClass {
// Approved classes (i.e. from your routine) can write, delete, clear...
internal readonly List<Data> m_Data = new List<Data>();
// All the other can only read
public IReadOnlyList<Data> Data {
get {
return m_Data;
}
}
...
// If you let (in some cases) add, delete, clear to untrusted class
// just add appropriate methods:
public void Add(Data data) {
// Here you can validate the provided data, check conditions, state etc.
}
}
If you want to publish a collection with add/remove capability, it is the best if you override the Collection<T> (or ObservableCollection<T>) class, which is very similar to List<T>, but you can override and thus control the add/remove/replace operations. And yes, you can make it public via a get-only property.
public class MyClass
{
private MyCollection myCollection = new MyCollection();
public IList<MyElement> Collection { get { return myCollection; } }
}
internal class MyCollection: Collection<MyElement>
{
// by overriding InsertItem you can control Add and Insert
protected override InsertItem(int index, MyElement item)
{
if (CheckItem(item))
base.InsertItem(index, item);
throw new ArgumentException("blah");
}
// similarly, you can override RemoveItem to control Remove and RemoveAt,
// and SetItem to control the setting by the indexer (this[])
}

Enumerator with hidden options

I'm trying to create an excel document generator project. Currently i'm working on cell styles part.
So i have next structure:
public class Styles : List<Style>, ISerializableClass
{
...some special methods...
}
The thing i want to achieve:
When some Style ( item ) is being added to the Styles i want to automatically add/modify/update the Style id.
In other words i want to override the base list.Add() behavior. How can i achieve this?
Or i just should add this method in my Styles class:
public void Add(Style style)
{
/*
* Some mu logic
*/
base.Add(style);
}
To hide the default List.Add() method?
The best practice is to implement IList<T> yourself instead of inheriting from List<T>. You can then delegate most of the implementation to a List<T> field:
public class Styles : IList<Style>, ISerializableClass
{
private List<Style> _list = new List<Style>();
public void Add(Style style)
{
// Your stuff here
_list.Add(style);
}
// ...
}
See this question for more details about why inheriting from List<T> is not a good idea.
And you should almost always avoid hiding base class methods. Because this is easily defeated with code such as:
var stylesList = new Styles(); // Suppose this hides List<T>.Add
var castedList = (IList<Styles>)stylesList;
castedList.Add(new Style()); // <-- this still calls List<T>.Add
IMHO, the only acceptable use case for method hiding is in situations like IEnumerable<T>.GetEnumerator() hiding IEnumerable.GetEnumerator() where both methods do exactly the same thing anyway.

What's the best practice for alternate solution of Multi-Inheritance in C#

I have some classes inherit from existing Windows Controls like TextBox and DateTimePicker, ..etc
I want to add custom functionalities for these classes like (Read, Alert, ...etc)
these added functionalities are the same in all these classes
The problem is: these classes inherited from difference parents so I can't put my added functionalities in the parent class,
What's the best practice in this case:
repeat the code in each inherited
class
Use a separated class have the
functionalities as Static Methods
with parameter from an interface, implement this interface for the classes and
then pass them.
Use a separated class like the second approach but with Dynamic parameter (which added in C# 4.0)
or other !!
Thanks in advance
I'd consider option 4: composition.
First, define your set of functionality. We'll assume that your partial list is exclusive, so "Read" and "Alert."
Second, create a single class that implements this functionality, something like MyCommonControlBehaviors. I'd prefer this implementation not be static if possible, though, it may be generic.
public MyCommonControlBehaviors
{
public Whatever Read() { /* ... */ }
public void Alert() {}
}
Third, use composition to add an instance of this class to each of your custom control types and expose that functionality through your custom control:
public class MyCustomControl
{
private MyCommonControlBehaviors common; // Composition
public Whatever Read() { return this.common.Read(); }
public void Alert() { this.common.Alert(); }
}
Depending on specifics, you can get creative to the degree necessary. E.g., perhaps your custom behaviors need to interact with private control data. In that case, make your control implement a common ICommonBehaviorHost interface that your common behaviors need. Then pass the control into the behavior class on construction as an instance of ICommonBehaviorHost:
public interface ICommonBehaviorHost
{
void Notify();
}
public class MyCommonControlBehaviors
{
ICommonBehaviorHost hst = null;
public MyCommonControlBehaviors(ICommonBehaviorHost host)
{
this.hst = host;
}
public void Alert() { this.hst.Notify(); } // Calls back into the hosting control
// ...
}
public class MyCustomControl : ICommonBehaviorHost
{
private MyCommonControlBehaviors common = null;
public MyCustomControl() { common = new MyCommonControlBehaviors(this); }
public Whatever Read() { return this.common.Read(); }
public void Alert() { this.common.Alert(); }
void ICommonBehaviorHost.Notify() { /* called by this.common */ }
}
Use Composition instead of Inheritence!
If you must, what I would probably do is create extension methods for each class and then reference the actual coded needed for these in some other object all the extension methods can call.
This way the code isn't duplicated, and the extension methods make it look like the methods should be in the object.
It's the same essentially by creating a static method and doing: Functions.DoSomething(my_Object);
But I always like: my_Object.DoSomething() better in an OO language.
I would suggest defining an interface for the behaviors, and then (to keep from repeating yourself) create extension methods on that interface definition for your shared methods. (Kinda like your second option, only with extension methods instead of totally static methods).

Why is ReadOnlyObservableCollection.CollectionChanged not public?

Why is ReadOnlyObservableCollection.CollectionChanged protected and not public (as the corresponding ObservableCollection.CollectionChanged is)?
What is the use of a collection implementing INotifyCollectionChanged if I can't access the CollectionChanged event?
Here's the solution: CollectionChanged events on ReadOnlyObservableCollection
You have to cast the collection to INotifyCollectionChanged.
I've found a way for you of how to do this:
ObservableCollection<string> obsCollection = new ObservableCollection<string>();
INotifyCollectionChanged collection = new ReadOnlyObservableCollection<string>(obsCollection);
collection.CollectionChanged += new NotifyCollectionChangedEventHandler(collection_CollectionChanged);
You just need to refer to your collection explicitly by INotifyCollectionChanged interface.
I know this post is old, however, people should take their time to understand the patterns used in .NET before commenting. A read only collection is a wrapper on an existing collection that prevents consumers from modifying it directly, look at ReadOnlyCollection and you will see that it is a wrapper on a IList<T> which may or may not be mutable. Immutable collections are a different matter and are covered by the new immutable collections library
In other words, read only is not the same as immutable!!!!
That aside, ReadOnlyObservableCollection should implicitly implement INotifyCollectionChanged.
There are definitely good reasons for wanting to subscribe to collection changed notifications on a ReadOnlyObservableCollection. So, as an alternative to merely casting your collection as INotifyCollectionChanged, if you happen to be subclassing ReadOnlyObservableCollection, then the following provides a more syntactically convenient way to access the a CollectionChanged event:
public class ReadOnlyObservableCollectionWithCollectionChangeNotifications<T> : ReadOnlyObservableCollection<T>
{
public ReadOnlyObservableCollectionWithCollectionChangeNotifications(ObservableCollection<T> list)
: base(list)
{
}
event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged2
{
add { CollectionChanged += value; }
remove { CollectionChanged -= value; }
}
}
This has worked well for me before.
You might vote for the bug entry on Microsoft Connect that describes this issue: https://connect.microsoft.com/VisualStudio/feedback/details/641395/readonlyobservablecollection-t-collectionchanged-event-should-be-public
Update:
The Connect portal has been shutdown by Microsoft. So the link above does not work anymore.
My Win Application Framework (WAF) library provides a solution: ReadOnlyObservableList class:
public class ReadOnlyObservableList<T>
: ReadOnlyObservableCollection<T>, IReadOnlyObservableList<T>
{
public ReadOnlyObservableList(ObservableCollection<T> list)
: base(list)
{
}
public new event NotifyCollectionChangedEventHandler CollectionChanged
{
add { base.CollectionChanged += value; }
remove { base.CollectionChanged -= value; }
}
public new event PropertyChangedEventHandler PropertyChanged
{
add { base.PropertyChanged += value; }
remove { base.PropertyChanged -= value; }
}
}
As answered already, you have two options: you can either cast the ReadOnlyObservableCollection<T> to the interface INotifyCollectionChanged to access the explicitly implemented CollectionChanged event, or you can create your own wrapper class that does that once in the constructor and just hooks up the events of the wrapped ReadOnlyObservableCollection<T>.
Some additional insights into why this issue has not been fixed yet:
As you can see from the source code, ReadOnlyObservableCollection<T> is a public, non-sealed (i. e. inheritable) class, where the events are marked protected virtual.
That is, there might be compiled programs with classes that are derived from ReadOnlyObservableCollection<T>, with overridden event definitions but protected visibility. Those programs would contain invalid code once the event's visiblity is changed to public in the base class, because it is not allowed to restrict the visibility of an event in derived classes.
So unfortunately, making protected virtual events public later on is a binary-breaking change, and hence it will not be done without very good reasoning, which I am afraid "I have to cast the object once to attach handlers" simply isn't.
Source: GitHub comment by Nick Guerrera, August 19th, 2015
This was top hit on google so I figured I'd add my solution in case other people look this up.
Using the information above (about needing to cast to INotifyCollectionChanged), I made two extension methods to register and unregister.
My Solution - Extension Methods
public static void RegisterCollectionChanged(this INotifyCollectionChanged collection, NotifyCollectionChangedEventHandler handler)
{
collection.CollectionChanged += handler;
}
public static void UnregisterCollectionChanged(this INotifyCollectionChanged collection, NotifyCollectionChangedEventHandler handler)
{
collection.CollectionChanged -= handler;
}
Example
IThing.cs
public interface IThing
{
string Name { get; }
ReadOnlyObservableCollection<int> Values { get; }
}
Using the Extension Methods
public void AddThing(IThing thing)
{
//...
thing.Values.RegisterCollectionChanged(this.HandleThingCollectionChanged);
}
public void RemoveThing(IThing thing)
{
//...
thing.Values.UnregisterCollectionChanged(this.HandleThingCollectionChanged);
}
OP's Solution
public void AddThing(IThing thing)
{
//...
INotifyCollectionChanged thingCollection = thing.Values;
thingCollection.CollectionChanged += this.HandleThingCollectionChanged;
}
public void RemoveThing(IThing thing)
{
//...
INotifyCollectionChanged thingCollection = thing.Values;
thingCollection.CollectionChanged -= this.HandleThingCollectionChanged;
}
Alternative 2
public void AddThing(IThing thing)
{
//...
(thing.Values as INotifyCollectionChanged).CollectionChanged += this.HandleThingCollectionChanged;
}
public void RemoveThing(IThing thing)
{
//...
(thing.Values as INotifyCollectionChanged).CollectionChanged -= this.HandleThingCollectionChanged;
}
Solution
ReadOnlyObservableCollection.CollectionChanged is not exposed (for valid reasons outlined in other answers), so let's make our own wrapper class that exposes it:
/// <summary>A wrapped <see cref="ReadOnlyObservableCollection{T}"/> that exposes the internal <see cref="CollectionChanged"/>"/>.</summary>
public class ObservableReadOnlyCollection<T> : ReadOnlyObservableCollection<T>
{
public new NotifyCollectionChangedEventHandler CollectionChanged;
public ObservableReadOnlyCollection(ObservableCollection<T> list) : base(list) { /* nada */ }
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs args) =>
CollectionChanged?.Invoke(this, args);
}
Explanation
People have asked why you would want to observe changes to a read-only collection, so I'll explain one of many valid situations; when the read-only collection wraps a private internal collection that can change.
Here's one such scenario:
Suppose you have a service that allows adding and removing items to an internal collection from outside the service. Now suppose you want to expose the values of the collection but you don't want consumers to manipulate the collection directly; so you wrap the internal collection in a ReadOnlyObservableCollection.
Note that in order to wrap the internal collection with ReadOnlyObservableCollection the internal collection is forced to derive from ObservableCollection by the constructor of ReadOnlyObservableCollection.
Now suppose you want to notify consumers of the service when the internal collection changes (and hence when the exposed ReadOnlyObservableCollection changes). Rather than rolling your own implementation you just want to expose the CollectionChanged of the ReadOnlyObservableCollection. Rather than forcing the consumer to make an assumption about the implementation of the ReadOnlyObservableCollection, you simply swap the ReadOnlyObservableCollection with this custom ObservableReadOnlyCollection, and you're done.
The ObservableReadOnlyCollection hides ReadOnlyObservableCollection.CollectionChanged with it's own, and simply passes on all the collection changed events to any attached event handler.

Tracking instances with generics and supporting subclasses

I've defined the following generic class
public class ManagedClass<T> where T : ManagedClass<T>
{
static ManagedClass()
{
Manager = new ObjectManager<T>();
}
public static ObjectManager<T> Manager { get; protected set; }
public ManagedClass()
{
Manager.Add( (T)this );
}
}
The idea is that I can use it like so:
class Product : ManagedClass<Product> {}
Now I can do something to the 7th product created like so:
Product.Manager.GetById(7).DoSomething();
The problem comes in if i try to use a derived class:
class ExtendedProduct : Product {}
now ExtendedProduct.Manager has a list of 'Products', and if i want to use a new function that I have added to ExtendedProduct (DoSomethingElse), I have to cast the object I get back like so:
((ExtendedProduct)ExtendedProduct.Manager.GetById(7)).DoSomethingElse();
This is a bit ugly, and the whole point of using generics for this is to avoid casting. I suppose I could add a static constructor to the derived class to set Manager = new ObjectManager() and add a new Manager.addObject( this ) in the derived class constructor, but It seems like there should be some better way of doing this using generics. Any suggestions?
The problem is that ExtendedProduct.Manager is the same thing as Product.Manager; the manager object can't act differently depending on where it's accessed from.
A couple of possibilities I can think of:
Hide the typecast inside the GetById method by making it generic:
Product.Manager.GetById<ExtendedProduct>(7).DoSomethingElse();
Use one ObjectManager instance per subclass, connecting them privately if needed
Option 1 reminds me of NHibernate's ICriteria interface. It's effectively the same as a typecast, but a little harder to accidentally break.
Really what you're running into is a weakness with Generics. Once your class has resolved what type it's using for generics, you're somewhat restricted in what you can do.
Normally, I'd say Dependency Injection would be a savior here, but since the problematic method is static, that muddies up the waters.
I'd say the best thing is to have the ObjectManager class do the work for you:
static public class ObjectManager<T>
{
... the code that already exists in ObjectManager ...
static public U GetById<U>(long id)
{
object obj = GetById(id);
if (obj is U)
return (U)obj;
return default(U);
}
}
Then, in your code:
ExtendedProduct.Manager.GetById<ExtendedProduct>(7).DoSomethingElse();
It's not really tons more elegant than casting, but may be one of the only solutions using Generics.

Categories