How to design a inherited collection - c#

I'm writing a program in C# that has a custom collection. The custom collection performs some useful aggregate functions (AllSuccessful, %Successful, etc) over it's members which are of type ResultInfo. I have several classes that derive from ResultInfo (UploadResultInfo, XUploadResultInfo, and YUploadResultInfo), and would like to have additional collections that inherit from ResultInfoCollection that have additional aggregate functions. The only problem with doing this as specified is that it leaves a useless
public void Add(ResultInfo item)
{
}
on the collection. Clarification: This method takes an argument of type ResultInfo, but a ResultInfo added to an UploadResultInfoCollection will throw an error. Is there an elegant way of solving my problem? I've considered generics but I don't quite know how that would work.

To define a generic class that handles any child of ResultInfo you just define it like
public class MyCollection<T> : ICollection<T>
where T : ResultInfo
{
... the required methods ... just use "T" instead of "ResultInfo" ...
public void Add(T item) {}
}
Later on you can use it by
MyCollection<FooResultInfo> coll = new MyCollection<FooResultInfo>();
Just try using them, they are not too difficult and learning by doing is the best way ...

I'm not sure how you are left with a useless Add method.
If the collection populates itself, you can make the Add method private.
If you want your "inherited" additional collections to not expose the Add method, use composition instead of inheritance.

Consider whether your useful methods actually need to be instance methods.
Do they need to maintain state when other operations happen or are they all possible using the publically avaialable (or internaally available) API?
If so then simply make them static methods (extension methods is probably a good idea) and don't worry about inheritance. If the methods are meaningful on IEnumerable<T> then so much the better, by doing this you make your utility functions vastly more usable and thus useful.
Using the resulting package of functions simply requires importing the relevant namespace.

If all you're doing is providing some extra methods to an otherwise existing collection type, then consider simply defining extension methods for that type and using a normal generic collection.

Related

Can I create a generic method in c# that accepts a type based on whether it contains a certain method or not?

I want to create a generic method that takes any class that implements a certain method, for example Print(), usually in such a case we need a common interface and then I would say something like : where T : ICustomInterface and the compiler would guarantee that type T contains any methods in that interface. However, in cases where I do not have access to the type, for example I can not modify the List class part of the System.Collections.Generic namespace to implement my interface, can you still achieve this functionality?
However, in cases where I do not have access to the type, for example I can not modify the List class part of the System.Collections.Generic namespace to implement my interface, can you still achieve this functionality?
Try this first:
public class customList<T> : List<T> where T : ICustomInterface{
}
According to SharpLab, it valid code. But you need proper compiler confirmation.
If it does not work, there is the MVVM way: "If you can not modify it, wrap it into something you can modify." Just put a List<T> inside of a custom class as private field and add all the List Functions you want, by simply relaying thhe cals it to the List<T> inside.
Edit:
I wanted to create a generic class that takes anything that implements an indexer, and then have a generic "Peek" method (look forward in a list, array, or anything that contains an indexer) based on the current state of this class etc
Unfortunately, "having a Indexer" is not something Generics can test. In .NET every class can be given a Indexer, as much as it can be given Functions, Fields and Properties.
Reflection can Identify Indexers. I only ever consider Reflection as a fallback, but it is one way.
Despite the checking limits of generics, you can define Indexers in a Interface, as much as you could Functions and Properties. At the end of the day, Indexers are propably mostly Syntax sugar for Function calls like properties are. While doing so would at a first glance exclude the Build-in List types, it is easy enough to sublcass them and have them implement the Interface.
Without being able to add an interface this is going to be pretty hard to accomplish is a type friendly manner. I don't know the usefulness of this, but it could be done:
public void Print(object myObj) {
var method = myObj.GetType().GetMethod("Print");
if (method != null) method.Invoke(this, null);
}
Can’t do what you’re asking exactly. But you could write a wrapper class that allows you to set a delegate for the required method, and use the wrapper in the type constraint.
class Printable
{
protected readonly Action _action;
public Printable(Action printAction)
{
_action = printAction;
}
public void Print()
{
_action();
}
}
void CallPrint<T>(T obj) where T : Printable
{
obj.Print();
}
var wrapper = new Printable( ()=> foo.Print() );
CallPrint(wrapper)(
You could do a similar thing for classes that have indexers, although you would use a Func instead of an Action.

Avoid Generic Lists in Base Class - Should I Follow the Same Rule for Dictionary?

I was advised to change a List<string> property to a Collection<string>, in a base class, because it is more appropriate for inheritance.
This 'rule' was referred to: https://msdn.microsoft.com/en-us/library/ms182142.aspx
System.Collections.Generic.List is a generic collection that is
designed for performance and not inheritance.
System.Collections.Generic.List does not contain virtual members
that make it easier to change the behavior of an inherited class. The
following generic collections are designed for inheritance and should
be exposed instead of System.Collections.Generic.List.
System.Collections.ObjectModel.Collection<T>
System.Collections.ObjectModel.ReadOnlyCollection<T>
System.Collections.ObjectModel.KeyedCollection<TKey, TItem>
Does a similar rule apply to Dictionary<string, string>?
I ask because it is also in the System.Collections.Generic namespace. Or maybe I have misunderstood and the rule only applies to Lists.
BTW, the Dictionary purpose is to hold errors (in a similar format to ModelState). I am not currently sure at exactly what stage I will be adding errors to it.
If I should be avoiding Dictionary<string, string> in the base class, what should I be using in it's place?
I have come across KeyedCollection but not sure if that is a good replacement.
Dictionary<TKey, TValue> does not have any base class you can use instead of it. It may be better to use interface (IDictionary<TKey, TValue> or maybe IReadOnlyDictionary<TKey, TValue> -both implemented by Dictionary), but it depends on your needs.
Note that it is very hard to express whether property returns internal storage or clone (and hence what happens when caller changes object) - you may want to consider IEnumerable<T> or methods that hide dictionary as implementation details.
So basically what you were told could potentially be wrong for the use case you are going for.
The statement in the msdn article means by inheritance if you want to create your own implementation of a collection by deriving from it like so:
public class MyCollection : Collection<MyType>
The advantage of using Collection<T> in this scenario is that you can alter the behavior significantly as it exposes the following methods which can be overriden: ClearItems, InsertItem, RemoveItem and SetItem. When you derive from List<T> you can't override any methods at all (except for the standard ToString, Equals and GetHashCode).
But as you stated in your comment you use the List/Dictionary/Collection as a property. Therefore it rather depends on your own use case.
If you want deriving classes to just use the collection from the base class you can let it be whatever you think is best suited for your needs. But if you think that the deriving class will know better which collection to use then you should
pick an interface from the System.Collections.Generic namespace.
I won't tell you which types or interfaces you should use when as it heavily depends on which functionality you need.
And by the way: the KeyedCollection can only be used to create your own key value collection (it is abstract). Therefore having a KeyedCollection as a property would mean that you'd also need an implementaion of a KeyedCollection.

Inheriting from List<myType> or Extending List<myType>

If I'm creating a class, MyWrapper, to wrap a List of objects from myClass, should MyWrapper inherit from List<T>? Or List<myClass>?
Or should I just create some extension methods for List<myClass>?
I know it's against the guideliness to inherit from List<T>, but why?
Is there any drawback for inheriting from List<Point> or List<T>?
Is there any drawback for creating extension methods for List<T>? And what about creating extension methods for List<myType>?
And a example for a extension method valid for List would be
public static void Swap<T>(this List<T> list, int firstIndex, int secondIndex)
{...}
You can't just add extension methods to List, because you won't be able to code to the shape of all types of T. What if it's a List<People>? What would "MoveTo" or "GetCenter" do in that case?
Yes, you should make a new class that inherits from List, or better yet, IList.
Or you could just model your "Point" class, then have a List<Point>, and if you wanted to add extension methods to List<Point> you could do that.
If you choose to derive List<>, the most evident drawback is that your user can't "guess" which method is overriden, and which ones is provided "as is". List is very rich class, especially when extended with LINQ, and a custom overriding of it can quickly be misleading and bug prone.
If you would like to provide List "as is", with a few custom methods, Extension Methods for List (where you target your specific kind of "T" !) could be really helpful and allow to preserve the original behavior of List.
Users will enable and use your Extension Methods only if they need them.
The drawbacks are the evident ones of Extension Methods : you can't do everything you want in them. There are plenty informations on web on Extension Methods.
IHMO the best thing to do is to encapsulate the List (or other enumerable) in your own class. Of course, T is specific to your own case.
The drawback is the need to redefine all relevant methods. Of course you can also expose the inner list (or, better, a Read only copy of it) with a specific property to allow user to directly use it. Your class can also implement IEnumerable.
Please also note that there are already tons of useful rewriting and extending methods and full custom collection implementation to improve List and other collections types on the web, and in Framework itself (most of collection types are misused, and LINQ adds a lot of good things). Take care to not reinvent the wheel.

How to override List<T>.IsReadOnly in C#

I'm trying to derive from List and selectively turn the IsReadOnly property on and off. I was hoping that the Add/Remove/[] functions would honor this property, but they don't.
What's the right way of doing this?
My derived class has some additional properties, so I can't unfortunately just wrap the list in ReadOnlyCollection.
Use encapsulation instead of inheritance in this case.
You should just make your class implement IList<T>, and have a private List<T> variable.
You can pass through any functions you wish, but also can completely override them, change behavior, etc. This gives you complete control (at the expense of having many methods that does nothing but call this.List.method(...) ).
In general, I don't think it's a good idea to inherit from the BCL collection classes in any case. I prefer to make them an implementation detail internal in my class.
List<T> is by definition a mutable type. There's no way to make it read-only.
If you're making a derived class, you should probably be implementing IList<T> directly rather than subclassing List<T> anyway. This will give you full control over the implementation, allowing you to make it read-only if you wish.
You could call the "AsReadOnly" method on list which should return to you an IList instance that should honor that it is...err...read-only.
...OK, I just read your last sentence, my bad. In which case maybe you just want to implement the IList interface or any friend and just route most of the interface to a list you keep internally. Then you can build this behaviour. Even so, I would do a similar pattern, provide some "AsReadOnly" method that explicitly gives you something that is read-only.

Collection<T> versus List<T> what should you use on your interfaces?

The code looks like below:
namespace Test
{
public interface IMyClass
{
List<IMyClass> GetList();
}
public class MyClass : IMyClass
{
public List<IMyClass> GetList()
{
return new List<IMyClass>();
}
}
}
When I Run Code Analysis i get the following recommendation.
Warning 3 CA1002 : Microsoft.Design : Change 'List' in 'IMyClass.GetList()' to use Collection, ReadOnlyCollection or KeyedCollection
How should I fix this and what is good practice here?
To answer the "why" part of the question as to why not List<T>, The reasons are future-proofing and API simplicity.
Future-proofing
List<T> is not designed to be easily extensible by subclassing it; it is designed to be fast for internal implementations. You'll notice the methods on it are not virtual and so cannot be overridden, and there are no hooks into its Add/Insert/Remove operations.
This means that if you need to alter the behavior of the collection in the future (e.g. to reject null objects that people try to add, or to perform additional work when this happens such as updating your class state) then you need to change the type of collection you return to one you can subclass, which will be a breaking interface change (of course changing the semantics of things like not allowing null may also be an interface change, but things like updating your internal class state would not be).
So by returning either a class that can be easily subclassed such as Collection<T> or an interface such as IList<T>, ICollection<T> or IEnumerable<T> you can change your internal implementation to be a different collection type to meet your needs, without breaking the code of consumers because it can still be returned as the type they are expecting.
API Simplicity
List<T> contains a lot of useful operations such as BinarySearch, Sort and so on. However if this is a collection you are exposing then it is likely that you control the semantics of the list, and not the consumers. So while your class internally may need these operations it is very unlikely that consumers of your class would want to (or even should) call them.
As such, by offering a simpler collection class or interface, you reduce the number of members that users of your API see, and make it easier for them to use.
I would personally declare it to return an interface rather than a concrete collection. If you really want list access, use IList<T>. Otherwise, consider ICollection<T> and IEnumerable<T>.
I don't think anyone has answered the "why" part yet... so here goes. The reason "why" you "should" use a Collection<T> instead of a List<T> is because if you expose a List<T>, then anyone who gets access to your object can modify the items in the list. Whereas Collection<T> is supposed to indicate that you are making your own "Add", "Remove", etc methods.
You likely don't need to worry about it, because you're probably coding the interface for yourself only (or maybe a few collegues). Here's another example that might make sense.
If you have a public array, ex:
public int[] MyIntegers { get; }
You would think that because there is only a "get" accessor that no-one can mess with the values, but that's not true. Anyone can change the values inside there just like this:
someObject.MyIngegers[3] = 12345;
Personally, I would just use List<T> in most cases. But if you are designing a class library that you are going to give out to random developers, and you need to rely on the state of the objects... then you'll want to make your own Collection and lock it down from there :)
It's mostly about abstracting your own implementations away instead of exposing the List object to be manipulated directly.
It's not good practice to let other objects (or people) modify the state of your objects directly. Think property getters/setters.
Collection -> For normal collection
ReadOnlyCollection -> For collections that shouldn't be modified
KeyedCollection -> When you want dictionaries instead.
How to fix it depends on what you want your class to do and the purpose of the GetList() method. Can you elaborate?
In these kind of case I usually try to expose the least amount of implemententation that is needed. If the consumers do not need to know that you are actually using a list then you don't need to return a list. By returning as Microsoft suggests a Collection you hide the fact that you are using a list from the consumers of your class and isolate them against an internal change.
Something to add though it's been a long time since this was asked.
When your list type derives from List<T> instead of Collection<T>, you cannot implement the protected virtual methods that Collection<T> implements.
What this means is that you derived type cannot respond in case any modifications are made to the list. This is because List<T> assumes you are aware when you add or remove items. Being able to response to notifications is an overhead and hence List<T> doesn't offer it.
In cases when external code has access to your collection, you may not be in control of when an item is being added or removed. Therefore Collection<T> provides a way to know when your list was modified.
I don't see any problem with returning something like
this.InternalData.Filter(crteria).ToList();
If I returned a disconnected copy of internal data, or detached result of a data query - I can safely return List<TItem> without exposing any of implementation details, and allow to use the returned data in the convenient way.
But this depends on what type of consumer I expect - if this is a something like data grid I prefer to return IEnumerable<TItem> which will be the copied list of items anyway in most cases :)
Well the Collection class is really just a wrapper class around other collections to hide their implementation details and other features. I reckon this has something to do with the property hiding coding pattern in object-oriented languages.
I think you shouldn't worry about it, but if you really want to please the code analysis tool, just do the following:
//using System.Collections.ObjectModel;
Collection<MyClass> myCollection = new Collection<MyClass>(myList);

Categories