If I have a method that requires a parameter that,
Has a Count property
Has an integer indexer (get-only)
What should the type of this parameter be? I would choose IList<T> before .NET 4.5 since there was no other indexable collection interface for this and arrays implement it, which is a big plus.
But .NET 4.5 introduces the new IReadOnlyList<T> interface and I want my method to support that, too. How can I write this method to support both IList<T> and IReadOnlyList<T> without violating the basic principles like DRY?
Edit: Daniel's answer gave me some ideas:
public void Foo<T>(IList<T> list)
=> Foo(list, list.Count, (c, i) => c[i]);
public void Foo<T>(IReadOnlyList<T> list)
=> Foo(list, list.Count, (c, i) => c[i]);
private void Foo<TList, TItem>(
TList list, int count, Func<TList, int, TItem> indexer)
where TList : IEnumerable<TItem>
{
// Stuff
}
Edit 2: Or I could just accept an IReadOnlyList<T> and provide a helper like this:
public static class CollectionEx
{
public static IReadOnlyList<T> AsReadOnly<T>(this IList<T> list)
{
if (list == null)
throw new ArgumentNullException(nameof(list));
return list as IReadOnlyList<T> ?? new ReadOnlyWrapper<T>(list);
}
private sealed class ReadOnlyWrapper<T> : IReadOnlyList<T>
{
private readonly IList<T> _list;
public ReadOnlyWrapper(IList<T> list) => _list = list;
public int Count => _list.Count;
public T this[int index] => _list[index];
public IEnumerator<T> GetEnumerator() => _list.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
Then I could call it like Foo(list.AsReadOnly())
Edit 3: Arrays implement both IList<T> and IReadOnlyList<T>, so does the List<T> class. This makes it pretty rare to find a class that implements IList<T> but not IReadOnlyList<T>.
You are out of luck here. IList<T> doesn't implement IReadOnlyList<T>. List<T> does implement both interfaces, but I think that's not what you want.
However, you can use LINQ:
The Count() extension method internally checks whether the instance in fact is a collection and then uses the Count property.
The ElementAt() extension method internally checks whether the instance in fact is a list and than uses the indexer.
Since IList<T> and IReadOnlyList<T> do not share any useful "ancestor", and if you don't want your method to accept any other type of parameter, the only thing you can do is provide two overloads.
If you decide that reusing codes is a top priority then you could have these overloads forward the call to a private method that accepts IEnumerable<T> and uses LINQ in the manner Daniel suggests, in effect letting LINQ do the normalization at runtime.
However IMHO it would probably be better to just copy/paste the code once and just keep two independent overloads that differ on just the type of argument; I don't believe that micro-architecture of this scale offers anything tangible, and on the other hand it requires non-obvious maneuvers and is slower.
If you're more concerned with maintaining the principal of DRY over performance, you could use dynamic, like so:
public void Do<T>(IList<T> collection)
{
DoInternal(collection, collection.Count, i => collection[i]);
}
public void Do<T>(IReadOnlyList<T> collection)
{
DoInternal(collection, collection.Count, i => collection[i]);
}
private void DoInternal(dynamic collection, int count, Func<int, T> indexer)
{
// Get the count.
int count = collection.Count;
}
However, I can't say in good faith that I'd recommend this as the pitfalls are too great:
Every call on collection in DoInternal will be resolved at run time. You lose type safety, compile-time checks, etc.
Performance degradation (while not severe, for the singular case, but can be when aggregated) will occur
Your helper suggestion is the most useful, but I think you should flip it around; given that the IReadOnlyList<T> interface was introduced in .NET 4.5, many API's don't have support for it, but have support for the IList<T> interface.
That said, you should create an AsList wrapper, which takes an IReadOnlyList<T> and returns a wrapper in an IList<T> implementation.
However, if you want to emphasize on your API that you are taking an IReadOnlyList<T> (to emphasize the fact that you aren't mutating the data), then the AsReadOnlyList extension that you have now would be more appropriate, but I'd make the following optimization to AsReadOnly:
public static IReadOnlyList<T> AsReadOnly<T>(this IList<T> collection)
{
if (collection == null)
throw new ArgumentNullException("collection");
// Type-sniff, no need to create a wrapper when collection
// is an IReadOnlyList<T> *already*.
IReadOnlyList<T> list = collection as IReadOnlyList<T>;
// If not null, return that.
if (list != null) return list;
// Wrap.
return new ReadOnlyWrapper<T>(collection);
}
What you need is the IReadOnlyCollection<T> available in .Net 4.5 which is essentially an IEnumerable<T> which has Count as the property but if you need indexing as well then you need IReadOnlyList<T> which would also give an indexer.
I don't know about you but I think this interface is a must have that had been missing for a very long time.
Related
Is there a simple implementation of ICollection<T> in .NET framework? I.e. a collection class with ability to add and remove items, but without indexing. Collection<T> definitely does not fit, as it implements IList as well and so elements can be accessed by index.
Exposing Collection<T> or List<T> as ICollection<T> will not work in my case too, because I need to inherit my own class from it, and a class inherited from any other class that implements IList<T> will have indexing as well.
I know it is not a big deal to implement one myself, but just thought it should already exist, searched for but did not found anything similar.
Here's a list of classes that implement ICollection<T> in the System.Collections namespace:
System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>
System.Collections.Generic.Dictionary<TKey, TValue>
System.Collections.Generic.HashSet<T>
System.Collections.Generic.LinkedList<T>
System.Collections.Generic.List<T>
System.Collections.Generic.SortedDictionary<TKey, TValue>
System.Collections.Generic.SortedList<TKey, TValue>
System.Collections.Generic.SortedSet<T>
System.Collections.ObjectModel.Collection<T>
System.Collections.ObjectModel.ReadOnlyCollection<T>
System.Collections.ObjectModel.ReadOnlyDictionary<TKey, TValue>
System.Collections.ObjectModel.WeakReadOnlyCollection<T>
But all of those implementations add extra functionality, and since you want to inherit from an implementation, but only expose ICollection<T> methods, using any of them is not really an option.
The only choice you have is to implement your own. It's easy enough to do. You just need to wrap a suitable implementation of ICollection<T>. Here's one that uses a List<T> by default, but also allows derived classes to use a specific type of ICollection<T>:
class SimpleCollection<T> : ICollection<T>
{
ICollection<T> _items;
public SimpleCollection() {
// Default to using a List<T>.
_items = new List<T>();
}
protected SimpleCollection(ICollection<T> collection) {
// Let derived classes specify the exact type of ICollection<T> to wrap.
_items = collection;
}
public void Add(T item) {
_items.Add(item);
}
public void Clear() {
_items.Clear();
}
public bool Contains(T item) {
return _items.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex) {
_items.CopyTo(array, arrayIndex);
}
public int Count
{
get { return _items.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
return _items.Remove(item);
}
public IEnumerator<T> GetEnumerator()
{
return _items.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _items.GetEnumerator();
}
}
This is going beyond what you're after, but if, for example, you wanted unique items to be stored, you could derive from this and provide a HashSet<T> as the collection type to wrap:
class UniqueCollection<T> : SimpleCollection<T>
{
public UniqueCollection() : base(new HashSet<T>()) {}
}
Hashset<T>
should work if you would like it to be unordered with unique values.
See MSDN
As mentioned in the comments, ICollection<T> is an even simpler collection that is unordered and will allow duplicate entries. MSDN
ICollection<string> unordered = new Collection<string>();
Finally, I am not aware of a "simple" native .NET implementation of a collection that has .Add() / .Remove() functionality without exposing an index. So, to answer your question, it looks like for your niche functionality you'll have to roll your own.
Just to give a quick differences:
SortedList
Is the best way to use to by get keys rather index and it is based on binary search. Internally, it uses two lists: IList and IList. It does not use Dictionary. Thus it does not have any Hash values.
SortedDictionary is same as SortedList. However, the difference is internal development. Sorted Dictionary is using B Tree. Thus modifications are fast, and lookups are same as sorted list.
Difference between HashSet and List is HashSet ensures uniqueness. That means if you try to add the value twice, it will ignore that value without giving any error or duplicating the same.
So if you don't want to use index based then you can use SortedList that is inherited from ICollection and then IEnumerable...
Otherwise HashSet is the best option where uniqueness is important.
I had a generic extension method
public static IList<T> Replace<T>(this IList<T> source, Ilist<T> newList) where T:IStateful
which I called using
myStatefulSetOfStuff = myStatefulSetOfStuff.Replace(GetNewSetOfStuff());
I realized, though, that my method would work on all collections that implement ICollection, so I changed it to
public static ICollection<T> Replace<T>(this ICollection<T> source, ICollection<T> newList) where T:IStateful
However, now the method returns an IColllection, which forces me to write the call as:
myStatefulSetOfStuff = myStatefulSetOfStuff.Replace(GetNewSetOfStuff()).ToList();
How can I re-write my method so that I don't need the .ToList() on my call?
EDIT:
There seemes to be some confusion, so I'll try to clear it up. I have a list. I want to perform an operation on that list with a new list. No problem. And I figured out how to return a List with an extension method.
But I realized, hey, the actual code in Replace() isn't specific to Lists, it can apply to any collection. So I modified Replace to return an ICollection. This then forces the calling method to look like
var newStuff = left.Replace(right).ToList()
or
var newStuff = left.Replace(right).ToArray()
etc.
But I don't want to say ToList, ToArray, etc., I want the method to just infer the correct return type from the source object. So I can say
var newStuff = left.Replace(right);
and newStuff will be of the same type as left. Right will be of the same type as well.
Try the following
public static TCollection Replace<TCollection, TItem>(
this TCollection source,
TCollection newList)
where TCollection : ICollection<TItem>
where TItem : IStateful
Here's a use case example
interface IStateful { }
class Foo : IStateful { }
static void Test()
{
ICollection<Foo> left = null, right= null;
left.Replace<ICollection<Foo>, Foo>(right);
}
Unfortunately the generic parameters do appear necessary in this scenario (can't get type inference to work for this specific scenario)
EDIT
My answer is based off of a bit of a misread of the question. I thought the intent was to flow the type of the source to the return type of the method. Upon further re-reading though it appears you want instead to flow any source and return an List in all cases. In which case I suggest you take a look at Reed's answer.
If you need it to always return IList<T>, just change it to:
public static IList<T> Replace<T>(this ICollection<T> source, ICollection<T> newList) where T:IStateful
And put the .ToList() call inside your extension method (unless it's already creating a list internally).
That being said, you can "nest" this by having two type parameters, if you wish to do so.
I want to declare a dictionary that stores typed IEnumerable's of a specific type, with that exact type as key, like so: (Edited to follow johny g's comment)
private IDictionary<Type, IEnumerable<T>> _dataOfType where T: BaseClass; //does not compile!
The concrete classes I want to store, all derive from BaseClass, therefore the idea to use it as constraint. The compiler complains that it expects a semicolon after the member name.
If it would work, I would expect this would make the later retrieval from the dictionary simple like:
IEnumerable<ConcreteData> concreteData;
_sitesOfType.TryGetValue(typeof(ConcreteType), out concreteData);
How to define such a dictionary?
Use System.ComponentModel.Design.ServiceContainer that is already available in .Net framework.
ServiceContainer container = new ServiceContainer();
IList<int> integers = new List<int>();
IList<string> strings = new List<string>();
IList<double> doubles = new List<double>();
container.AddService(typeof(IEnumerable<int>), integers);
container.AddService(typeof(IEnumerable<string>), strings);
container.AddService(typeof(IEnumerable<double>), doubles);
You may not even need a dictionary to be able to do this - but that depends on your needs. If you only ever need 1 such list per type per appdomain (i.e. the "dictionary" is static), the following pattern can be efficient and promotes type-inference nicely:
interface IBase {}
static class Container {
static class PerType<T> where T : IBase {
public static IEnumerable<T> list;
}
public static IEnumerable<T> Get<T>() where T : IBase
=> PerType<T>.list;
public static void Set<T>(IEnumerable<T> newlist) where T : IBase
=> PerType<T>.list = newlist;
public static IEnumerable<T> GetByExample<T>(T ignoredExample) where T : IBase
=> Get<T>();
}
Note that you should think carefully before adopting this approach about the distinction between compile-time type and run-time type. This method will happily let you store a runtime-typed IEnumerable<SomeType> variable both under SomeType and -if you cast it- under any of SomeType's base types, including IBase, with neither a runtime nor compiletype error - which might be a feature, or a bug waiting to happen, so you may want an if to check that.
Additionally, this approach ignores threading; so if you want to access this data-structure from multiple threads, you probably want to add some locking. Reference read/writes are atomic, so you're not going to get corruption if you fail to lock, but stale data and race conditions are certainly possible.
You don't constrain T in the private member; you constrain it at the class level.
class Foo<T> where T : BaseClass
{
private IDictionary<T, IEnumerable<T>> _dataOfType;
public Foo(IDictionary<T, IEnumerable<T>> dataOfType)
{
this._dataOfType = dataOfType;
}
}
You can't constrain a specific variable. It only works on classes and methods. It really doesn't make any sense in the variable level, to be honest.
What you want is a custom class - class WeirdDictionary : IDictionary<Type, IEnumerable>, that will overload the Add method to take a Type and an IEnumerable of that type, which you can do using constraints, and cast the IEnumerable<> to IEnumerable. Overload the indexer aswell, and cast it back to the relevant type.
All this casting is needed, since generics are strict about IEnumerable<Base> being as good as IEnumerable<Derived> (This is called variance, I believe?)
This solution is slightly generalized, since reuse rocks
Edit by 280Z28:
At first I marked this down because point #2 was confusing and I misinterpreted it. By using explicit implementation of methods in IDictionary<Type, IEnumerable> and providing generic alternatives, you can get a pretty clean interface. Note that you cannot create generic indexers, so you'll have to always use TryGet<T> (which is a good idea anyway). I only included explicit implementation of one of the IDictionary<> methods to show how to perform the checks. Do not derive WeirdDictionary directly from Dictionary<Type, IEnumerable> or you will lose the ability to guarantee constraints in the underlying data.
class WeirdDictionary : IDictionary<Type, IEnumerable>
{
private readonly Dictionary<Type, IEnumerable> _data =
new Dictionary<Type, IEnumerable>();
public void Add<T>(IEnumerable<T> value)
{
_data.Add(typeof(T), value);
}
public bool TryGet<T>(out IEnumerable<T> value)
{
IEnumerable enumerable;
if (_data.TryGetValue(typeof(T), out enumerable)
{
value = (IEnumerable<T>)enumerable;
return true;
}
value = null;
return false;
}
// use explicit implementation to discourage use of this method since
// the manual type checking is much slower that the generic version above
void IDictionary<Type, IEnumerable>.Add(Type key, IEnumerable value)
{
if (key == null)
throw new ArgumentNullException("key");
if (value != null && !typeof(IEnumerable<>).MakeGenericType(key).IsAssignableFrom(value.GetType()))
throw new ArgumentException(string.Format("'value' does not implement IEnumerable<{0}>", key));
_data.Add(key, value);
}
}
End 280Z28
Make a custom Dictionary class:
public class BaseClassDictionary<T, IEnumerable<T>> : Dictionary<T, IEnumerable<T>>
where T : BaseClass
{
}
Then you can use this specialized dictionary instead as field type:
private BaseClassDictionary<BaseClassDerivedType, IEnumerable<BaseClassDerivedType>> myDictionary;
Try this:
public class MyCustomDictionary<T>: Dictionary<T, IEnumerable<T>> { }
This questions involves 2 different implementations of essentially the same code.
First, using delegate to create a Comparison method that can be used as a parameter when sorting a collection of objects:
class Foo
{
public static Comparison<Foo> BarComparison = delegate(Foo foo1, Foo foo2)
{
return foo1.Bar.CompareTo(foo2.Bar);
};
}
I use the above when I want to have a way of sorting a collection of Foo objects in a different way than my CompareTo function offers. For example:
List<Foo> fooList = new List<Foo>();
fooList.Sort(BarComparison);
Second, using IComparer:
public class BarComparer : IComparer<Foo>
{
public int Compare(Foo foo1, Foo foo2)
{
return foo1.Bar.CompareTo(foo2.Bar);
}
}
I use the above when I want to do a binary search for a Foo object in a collection of Foo objects. For example:
BarComparer comparer = new BarComparer();
List<Foo> fooList = new List<Foo>();
Foo foo = new Foo();
int index = fooList.BinarySearch(foo, comparer);
My questions are:
What are the advantages and disadvantages of each of these implementations?
What are some more ways to take advantage of each of these implementations?
Is there a way to combine these implementations in such a way that I do not need to duplicate the code?
Can I achieve both a binary search and an alternative collection sort using only 1 of these implementations?
There really is no advantage to either option in terms of performance. It's really a matter of convenience and code maintainability. Choose the option you prefer. That being said, the methods in question limit your choices slightly.
You can use the IComparer<T> interface for List<T>.Sort, which would allow you to not duplicate code.
Unfortunately, BinarySearch does not implement an option using a Comparison<T>, so you cannot use a Comparison<T> delegate for that method (at least not directly).
If you really wanted to use Comparison<T> for both, you could make a generic IComparer<T> implementation that took a Comparison<T> delegate in its constructor, and implemented IComparer<T>.
public class ComparisonComparer<T> : IComparer<T>
{
private Comparison<T> method;
public ComparisonComparer(Comparison<T> comparison)
{
this.method = comparison;
}
public int Compare(T arg1, T arg2)
{
return method(arg1, arg2);
}
}
Probably the biggest advantage to accepting a Comparison<T> as opposed to an IComparer<T> is the ability to write anonymous methods. If I have, let's say, a List<MyClass>, where MyClass contains an ID property that should be used for sorting, I can write:
myList.Sort((c1, c2) => c1.ID.CompareTo(c2.ID));
Which is a lot more convenient than having to write an entire IComparer<MyClass> implementation.
I'm not sure that accepting an IComparer<T> really has any major advantages, except for compatibility with legacy code (including .NET Framework classes). The Comparer<T>.Default property is only really useful for primitive types; everything else usually requires extra work to code against.
To avoid code duplication when I need to work with IComparer<T>, one thing I usually do is create a generic comparer, like this:
public class AnonymousComparer<T> : IComparer<T>
{
private Comparison<T> comparison;
public AnonymousComparer(Comparison<T> comparison)
{
if (comparison == null)
throw new ArgumentNullException("comparison");
this.comparison = comparison;
}
public int Compare(T x, T y)
{
return comparison(x, y);
}
}
This allows writing code such as:
myList.BinarySearch(item,
new AnonymousComparer<MyClass>(x.ID.CompareTo(y.ID)));
It's not exactly pretty, but it saves some time.
Another useful class I have is this one:
public class PropertyComparer<T, TProp> : IComparer<T>
where TProp : IComparable
{
private Func<T, TProp> func;
public PropertyComparer(Func<T, TProp> func)
{
if (func == null)
throw new ArgumentNullException("func");
this.func = func;
}
public int Compare(T x, T y)
{
TProp px = func(x);
TProp py = func(y);
return px.CompareTo(py);
}
}
Which you can write code designed for IComparer<T> as:
myList.BinarySearch(item, new PropertyComparer<MyClass, int>(c => c.ID));
The delegate technique is very short (lambda expressions might be even shorter), so if shorter code is your goal, then this is an advantage.
However, implementing the IComparer (and its generic equivalent) makes your code more testable: you can add some unit testing to your comparing class/method.
Furthermore, you can reuse your comparer implementation when composing two or more comparers and combining them as a new comparer. Code reuse with anonymous delegates is harder to achieve.
So, to sum it up:
Anonymous Delegates: shorter (and perhaps cleaner) code
Explicit Implementation: testability and code reuse.
They really address different needs:
IComparable is useful for objects that are ordered. Real numbers should be comparable, but complex numbers cannot - it is ill-defined.
IComparer allows to define re-usable, well-encapsulated comparers. This is especially useful if the comparison needs to know some additional information. For example, you might want to compare dates and times from different time zones. That can be complicated, and a separate comparer should be used for this purpose.
A comparison method is made for simple comparison operations that are not complicated enough for reusability to be of any concern, e.g. sorting a list of customers by their first name. This is simple operation, hence does not need additional data. Likewise, this is not inherent to the object, because the objects are not naturally ordered in any way.
Lastly, there is IEquatable, which might be important if your Equals method can only decide if two objects are equal or not, but if there is no notion of 'larger' and 'smaller', e.g. complex numbers, or vectors in space.
In your case, advantage of having an IComparer<T> over Comparision<T> delegate, is that you can also use it for the Sort method, so you don't need a Comparison delegate version at all.
Another useful thing you can do is implementing a delegated IComparer<T> implementation like this:
public class DelegatedComparer<T> : IComparer<T>
{
Func<T,T,int> _comparision;
public DelegatedComparer(Func<T,T,int> comparision)
{
_comparision = comparision;
}
public int Compare(T a,T b) { return _comparision(a,b); }
}
list.Sort(new DelegatedComparer<Foo>((foo1,foo2)=>foo1.Bar.CompareTo(foo2.Bar));
and a more advanced version:
public class PropertyDelegatorComparer<TSource,TProjected> : DelegatedComparer<TSource>
{
PropertyDelegatorComparer(Func<TSource,TProjected> projection)
: base((a,b)=>projection(a).CompareTo(projection(b)))
}
How do I get the type of a generic typed class within the class?
An example:
I build a generic typed collection implementing ICollection< T>. Within I have methods like
public void Add(T item){
...
}
public void Add(IEnumerable<T> enumItems){
...
}
How can I ask within the method for the given type T?
The reason for my question is: If object is used as T the collection uses Add(object item) instead of Add(IEnumerable<object> enumItems) even if the parameter is IEnumerable. So in the first case it would add the whole enumerable collection as one object instead of multiple objects of the enumerable collection.
So i need something like
if (T is object) {
// Check for IEnumerable
}
but of course that cannot work in C#. Suggestions?
Thank you very much!
Michael
You can use: typeof(T)
if (typeof(T) == typeof(object) ) {
// Check for IEnumerable
}
Personally, I would side step the issue by renaming the IEnumerable<T> method to AddRange. This avoids such issues, and is consistent with existing APIs such as List<T>.AddRange.
It also keeps things clean when the T you want to add implements IEnumerable<T> (rare, I'll admit).
If you want to use the is operator in a generic class/method you have to limit T to a reference type:
public void MyMethod<T>(T theItem) where T : class
{
if (theItem is IEnumerable) { DoStuff(); }
}