I have a method which I'd like to take all list-like objects in my solution. Before .NET 4.5, this was simple:
public static T Method<T>(IList<T> list)
{
// elided
}
However, .NET 4.5 introduced IReadOnlyList<T>, which this method should also apply to.
I can't just change the signature to take an IReadOnlyList<T>, as there are places where I apply the method to something specifically typed as an IList<T>.
The algorithm can't run on IEnumerable<T>, and it's used too frequently (and with too large objects) to take an IEnumerable<T> and create a new List<T> on every call.
I've tried adding an overload:
public static T Method<T>(IReadOnlyList<T> list)
{
// elided
}
... but this won't compile for anything which implements both interfaces (T[], List<T>, and numerous other types), as the compiler can't determine which method to use (particularly annoying as they have the same body, so it doesn't matter).
I don't want to have to add overloads of Method which take T[], and List<T>, and every other type which implements both interfaces.
How should I accomplish this?
This might be one of those occasions where actually checking the runtime type is useful:
public static T Method<T>(IEnumerable<T> source)
{
if (source is IList<T> list)
return Method(list);
if (source is IReadOnlyList<T> readOnly)
return Method(readOnly);
return Method(source.ToList() as IList<T>);
}
private static T Method<T>(IReadOnlyList<T> list) { ... }
private static T Method<T>(IList<T> list) { ... }
You still have to duplicate code in the sense that you need seperate implementations for IList and IReadOnlyList because there is no common interface you can leverage, but you at least avoid the ambigous call issue.
Your likely best bet is to do a global search and replace of IList to IReadOnlyList. If there are no compiler errors then you should be fine.
You should only receive compiler errors if you are using IList.Add - which is foolhardy anyway, since arrays don't support Add.
Can you change the code of Method calling?
What if you create a method like this:
public static T1 Method<T1, T2>(T2 list) where T2 : IList<T1>, IReadOnlyList<T1>
{
return default(T1);
}
In this case the calls look like this:
List<string> listA = new List<String>();
ReadOnlyCollection<string> listB = listA.AsReadOnly();
string outVar1 = Method<string, List<string>>(listA);
string outVar2 = Method<string, ReadOnlyCollection<string>>(listB);
Another way to create two extension methods for IList and IReadOnlyList this way:
public static T Test<T>(this IList<T> source)
{
return default(T);
}
public static T Test<T>(this IReadOnlyList<T> source)
{
return default(T);
}
And call them like this:
string outVar1 = (listA as IReadOnlyList<string>).Test();
string outVar2 = (listB as IList<string>).Test();
Maybe your best solution is to look into why your algorithm can't run on an IEnumerable and change that. Are you using IList<T> or IReadOnlyList<T> -specific members that you could replace with members available in IEnumerable<T>? Eg:
// instead of
int c = list.Count;
// use
int c = list.Count();
EDIT: ignore the nonsense below. I am leaving it so that the comments continue to make sense.
You should not implement both IList<T> and IReadOnlyList<T> in any class. The only additional members in the IList specification are for writing to the list. You would not need to do that if your list is read only. I think you need to change any classes that implement both so that the correct method can be selected when using them.
However, As all members of IReadOnlyList<T> are included in IList<T> (along with those derived from IReadOnlyCollection<T>) I wonder if the IList<T> in .Net should actually be changed so that it inherits the IReadOnlyList<T> interface rather than duplicating the members. Not that that helps you now.
Related
// Some interface method signature
public interface IList : ICollection {
...
bool Contains(Object value);
...
}
public interface IList<T> : ICollection<T> { ... }
public interface ICollection<T> : IEnumerable<T> {
...
bool Contains(T item);
...
}
Below is the source code of List: https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs
public class List<T> : IList<T>, System.Collections.IList, IReadOnlyList<T> {
...
public bool Contains(T item) {
...
}
bool System.Collections.IList.Contains(Object item) {
...
}
}
You can see that List uses explicit interface method implementation(explicitly specify the interface's name) to implement the non-generic Contains. But what I know about explicit interface method implementation is, you only do it when there are two interface methods that have the same signature.
But for public bool Contains(T item) and public bool Contains(Object item), they are different methods because they have different signatures (generic parameter and non-generic parameter), so List would have been implemented as:
public class List<T> : IList<T>, System.Collections.IList, IReadOnlyList<T> {
public bool Contains(T item) { ... }
public bool Contains(Object item) { ... }
}
Then why does List use an explicit interface method implementation to implement non-generic interface methods? I cannot see any benefit to use explicit interface method implementation in this scenario. Am I missing something here?
You can see that List uses explicit interface method implementation (explicitly specify the interface's name) to implement the non-generic Contains
Indeed.
But that's because the IList interface (not IList<T>) is decades-old - from the primitive, dark, times before .NET had support for generics (.NET 1.0 came out in 2001 - generics weren't added until the .NET Framework 2.0 in 2005). It was a truly godforsaken time.
List<T> (but not IList<T>) implements the IList interface so that the new generic List<T> could be consumed by older code that accepted an IList (in a way that allows preserving object identity and without requiring allocating a separate IList instance).
Supposing it's 2005 and you're writing some wonderous C# 2.0 code that uses the fancy new reified generics and List<T> - but you need to interact with a library that was last updated in 2004:
public void YourNewSexyGenericCode()
{
List<String> listOfString = new List<String>() { "a", "b", "c" };
OldAndBustedNET10CodeFrom2004( listOfString ); // <-- This works because List<String> implements IList.
foreach( String s in listOfString ) Console.WriteLine( s );
}
public void OldAndBustedNET10CodeFrom2004( IList listOfString )
{
listOfString.Add( "foo" );
listOfString.Add( "bar" );
listOfString.Add( "baz" );
return;
}
If List<T> didn't implement IList then you'd have to something horrible like this:
List<String> listOfString = new List<String>() { "a", "b", "c" };
// Step 1: Create a new separate IList and copy everything from your generic list into it.
IList classicList = new ArrayList();
classicList.AddRange( listOfString );
// Step 2: Pass the IList in:
OldAndBustedNET10CodeFrom2004( classicList );
// Step 3: Copy the elements back, in a type-safe manner:
foreach( Object maybeString in classicList )
{
String asString = maybeString as String; // The `is String str` syntax wasn't available back in C# 2.0
if( asString != null )
{
listOfString.Add( asString );
}
}
// Step 4: Continue:
foreach( String s in listOfString ) Console.WriteLine( s );
But what I know about explicit interface method implementation is, you only do it when there are two interface methods that have the same signature.
You are mistaken. There are many reasons to opt for explicit interface implementation besides implementing conflicting interfaces (such as hiding an implementation of an internal interface, implementing a type-theoretic unsound older/legacy interface for compatibility reasons (like IList), and for aesthetic reasons (reducing API clutter, though EditorBrowsable should be used for this).
But for public bool Contains(T item) and public bool Contains(Object item), they are different methods because they have different signatures (generic parameter and non-generic parameter), so List would have been implemented as...
In the paragraph above, I noted that IList is an type-theoretic unsound interface, that is: it allows you to do pointless and/or harmful things, for example:
List<String> listOfString = new List<String>() { "a", "b", "c" };
IList asIList = listOfString;
asIList.Add( new Person() );
The compiler will let this happen but it will crash at runtime because a List<String> cannot contain a Person. This is solved with reified generics thanks to .NET's support for covariance and contravariance (this is why you can safely implicitly convert any List<String> to IEnumerable<Object>, because String : Object, even though List<T> does not actually implement IEnumerable<Object>, but it does implement IEnumerable<T>).
Then why does List use an explicit interface method implementation to implement non-generic interface methods?
Because IList is a terrible interface that no-one should be using today, but some people were/are forced into using it because of legacy compatibility requirements. Everyone wants to see these legacy interfaces disappear (especially myself) but we can't because it would break binary application compatibility, which is essential for any runtime or platform to survive in the SWE ecosystem (this is also why the .NET team unfortunately has to turn-down many frequent requests that make sense but would break existing compiled programs (such as making IList<T> extend IReadOnlyList<T>).
I cannot see any benefit to use explicit interface method implementation in this scenario. Am I missing something here?
You were missing something - I hope my answer illuminates your mind.
Background:
Linq-To-Objects has the extension method Count() (the overload not taking a predicate). Of course sometimes when a method requires only an IEnumerable<out T> (to do Linq), we will really pass a "richer" object to it, such as an ICollection<T>. In that situation it would be wasteful to actually iterate through the entire collection (i.e. get the enumerator and "move next" a whole bunch of times) to determine the count, for there is a property ICollection<T>.Count for this purpose. And this "shortcut" has been used in the BCL since the beginning of Linq.
Now, since .NET 4.5 (of 2012), there is another very nice interface, namely IReadOnlyCollection<out T>. It is like the ICollection<T> except that it only includes those member that return a T. For that reason it can be covariant in T ("out T"), just like IEnumerable<out T>, and that is really nice when item types can be more or less derived. But the new interface has its own property, IReadOnlyCollection<out T>.Count. See elsewhere on SO why these Count properties are distinct (instead of just one property).
The question:
Linq's method Enumerable.Count(this source) does check for ICollection<T>.Count, but it does not check for IReadOnlyCollection<out T>.Count.
Given that it is really natural and common to use Linq on read-only collections, would it be a good idea to change the BCL to check for both interfaces? I guess it would require one additional type check.
And would that be a breaking change (given that they did not "remember" to do this from the 4.5 version where the new interface was introduced)?
Sample code
Run the code:
var x = new MyColl();
if (x.Count() == 1000000000)
{
}
var y = new MyOtherColl();
if (y.Count() == 1000000000)
{
}
where MyColl is a type implementing IReadOnlyCollection<> but not ICollection<>, and where MyOtherColl is a type implementing ICollection<>. Specifically I used the simple/minimal classes:
class MyColl : IReadOnlyCollection<Guid>
{
public int Count
{
get
{
Console.WriteLine("MyColl.Count called");
// Just for testing, implementation irrelevant:
return 0;
}
}
public IEnumerator<Guid> GetEnumerator()
{
Console.WriteLine("MyColl.GetEnumerator called");
// Just for testing, implementation irrelevant:
return ((IReadOnlyCollection<Guid>)(new Guid[] { })).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
Console.WriteLine("MyColl.System.Collections.IEnumerable.GetEnumerator called");
return GetEnumerator();
}
}
class MyOtherColl : ICollection<Guid>
{
public int Count
{
get
{
Console.WriteLine("MyOtherColl.Count called");
// Just for testing, implementation irrelevant:
return 0;
}
}
public bool IsReadOnly
{
get
{
return true;
}
}
public IEnumerator<Guid> GetEnumerator()
{
Console.WriteLine("MyOtherColl.GetEnumerator called");
// Just for testing, implementation irrelevant:
return ((IReadOnlyCollection<Guid>)(new Guid[] { })).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
Console.WriteLine("MyOtherColl.System.Collections.IEnumerable.GetEnumerator called");
return GetEnumerator();
}
public bool Contains(Guid item) { throw new NotImplementedException(); }
public void CopyTo(Guid[] array, int arrayIndex) { throw new NotImplementedException(); }
public bool Remove(Guid item) { throw new NotSupportedException(); }
public void Add(Guid item) { throw new NotSupportedException(); }
public void Clear() { throw new NotSupportedException(); }
}
and got the output:
MyColl.GetEnumerator called
MyOtherColl.Count called
from the code run, which shows that the "shortcut" was not used in the first case (IReadOnlyCollection<out T>). Same result is seen in 4.5 and 4.5.1.
UPDATE after comment elsewhere on Stack Overflow by user supercat.
Linq was introduced in .NET 3.5 (2008), of course, and the IReadOnlyCollection<> was introduced only in .NET 4.5 (2012). However, in between, another feature, covariance in generics was introduced, in .NET 4.0 (2010). As I said above, IEnumerable<out T> became a covariant interface. But ICollection<T> stayed invariant in T (since it contains members like void Add(T item);).
Already in 2010 (.NET 4) this had the consequence that if Linq's Count extension method was used on a source of compile-time type IEnumerable<Animal> where the actual run-time type was for example List<Cat>, say, which is surely an IEnumerable<Cat> but also, by covariance, an IEnumerable<Animal>, then the "shortcut" was not used. The Count extension method checks only if the run-time type is an ICollection<Animal>, which it is not (no covariance). It can't check for ICollection<Cat> (how would it know what a Cat is, its TSource parameter equals Animal?).
Let me give an example:
static void ProcessAnimals(IEnuemrable<Animal> animals)
{
int count = animals.Count(); // Linq extension Enumerable.Count<Animal>(animals)
// ...
}
then:
List<Animal> li1 = GetSome_HUGE_ListOfAnimals();
ProcessAnimals(li1); // fine, will use shortcut to ICollection<Animal>.Count property
List<Cat> li2 = GetSome_HUGE_ListOfCats();
ProcessAnimals(li2); // works, but inoptimal, will iterate through entire List<> to find count
My suggested check for IReadOnlyCollection<out T> would "repair" this issue too, since that is one covariant interface which is implemented by List<T>.
Conclusion:
Also checking for IReadOnlyCollection<TSource> would be beneficial in cases where the run-time type of source implements IReadOnlyCollection<> but not ICollection<> because the underlying collection class insists on being a read-only collection type and therefore wishes to not implement ICollection<>.
(new) Also checking for IReadOnlyCollection<TSource> is beneficial even when the type of source is both ICollection<> and IReadOnlyCollection<>, if generic covariance applies. Specifically, the IEnumerable<TSource> may really be an ICollection<SomeSpecializedSourceClass> where SomeSpecializedSourceClass is convertible by reference conversion to TSource. ICollection<> is not covariant. However, the check for IReadOnlyCollection<TSource> will work by covariance; any IReadOnlyCollection<SomeSpecializedSourceClass> is also an IReadOnlyCollection<TSource>, and the shortcut will be utilized.
The cost is one additional run-time type check per call to Linq's Count method.
In many cases a class that implements IReadOnlyCollection<T> will also implement ICollection<T>. So you will still profit from the Count property shortcut.
See ReadOnlyCollection for example.
public class ReadOnlyCollection<T> : IList<T>,
ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>,
IEnumerable<T>, IEnumerable
Since its bad practice to check for other interfaces to get access beyond the given readonly interface it should be ok this way.
Implementing an additional type check for IReadOnlyInterface<T> in Count() will be additional ballast for every call on an object which doesn't implement IReadOnlyInterface<T>.
Based on the MSDN documentation, ICollection<T> is the only type that gets this special treatment:
If the type of source implements ICollection<T>, that implementation is used to obtain the count of elements. Otherwise, this method determines the count.
I'm guessing they didn't see it as worthwhile to mess with the LINQ codebase (and its spec) for the sake of this optimization. There are lots of CLR types that have their own Count property, but LINQ can't account for all of them.
private static void PrintEachItemInList<T>(T anyList)
Where T:System.Collections.Generic.List<T>
{
foreach (var t in T)
{
//Do whatever
}
}
In the above code (which is wrong) all I want to do it to set a constraint that T is a List.
The aim is not to get this example to work, the aim is to understand how can I set a constraint that the type is a list? I am an amateur in generics and am trying to figure things out :(
Maybe you want two type parameters, as in:
private static void PrintEachItemInList<TList, TItem>(TList anyType)
where TList : System.Collections.Generic.List<TItem>
This is useful if you use classes that actually derive from List<>. If you want anything that acts as a list, consider constraining to the interface IList<> instead. It will then work for List<>, single-dimensional arrays, and custom classes implementing the interface (but not necessarily deriving from List<>).
Edit: As pointed out by the comment, this method is cumbersome to use because the compiler will not infer the two type arguments, so they will have to be given explicitly when calling the method.
Consider just using:
private static void PrintEachItemInList<TItem>(List<TItem> anyType)
Because anything which derives from a List<> is assignable to List<>, the method can be called with derived classes as arguments, and in many cases the type TItem can be inferred automatically by the compiler.
Still consider using the interface IList<>.
If all you want to do, is read from the list, use IReadOnlyList<TItem> instead of IList<TItem>. This signals to the caller that you won't change his list. Still no cast syntax is required when calling, for example: PrintEachItemInList(new[] { 2, 3, 5, 7, });. The type IReadOnlyList<> is new in .NET version 4.5.
If all you want to do is read from the list, and you don't want to use the indexer (no anyType[idx]), and you don't want to use the .Count property, and in fact, all you want to do is foreach through the list, use IEnumerable<TItem>. Again, you signal that you won't change people's lists.
Both IReadOnlyList<> and IEnumerable<> are covariant in their generic argument (type parameter).
Declare your input parameter as IList<T>. If you want to make your input sequence as abstract as possible - use IEnumerable<T> instead of IList<T>
private static void PrintEachItemInList<T>(IList<T> sequence)
{
foreach (T element in sequence)
{
//Do whatever
}
}
Your function should simply accept a list, and you don't need a constraint:
private static void PrintEachItemInList<T>(IList<T> list)
{
foreach (var t in list)
{
//Do whatever
}
}
However, if you only want to iterate the list you can make your code more general by changing the parameter type to one of these base interfaces:
IEnumerable<T> - allows foreach
IReadOnlyCollection - same as above and provides the count of elements in the collection
IReadOnlyList - same as above and allows element access by index
ICollection<T> - an IEnumerable<T> that provides an element count and methods to add and remove elements
IList<T> - same as above and allows you to add and remove elements by index
if you want to use parametric polymorphism to express that constraint, in c# you need two type parameters (since you don't get higher-order types):
private static void PrintEachItemInList<X, T>(X anyType) where X:System.Collections.Generic.List<T>
{
foreach (var t in anyType)
{
Console.WriteLine(t.ToString());
}
}
but then you need to call like this:
PrintEachItemInList<List<string>,string>(new List<string>() {"a", "b"});
You would typically write this as:
private static void PrintEachItemInList<T>(List<T> anyType)
{
// do work
}
However, in this case, I would recommend using IEnumerable<T> instead:
private static void PrintEachItemInList<T>(IEnumerable<T> anyType)
{
// do work
}
This will still allow you to use foreach but allow your method to be more flexible, as it will work work List<T> but also any other collection which implements IEnumerable<T>. If you must have list semantics within the method, you could use IList<T> , but your sample code (and method name) suggests IEnumerable<T> would be more appropriate.
I believe it's pretty stupid, and I am a bit embarrassed to ask this kind of question, but I still could not find the answer:
I am looking at the class List<T> , which implemetns IList.
public class List<T> : IList
one of the methods included in Ilist is
int Add(object value)
I understand that List<T> should not expose that method (type safety...), and it really does not. But how can it be? mustnt class implement the entire interface?
I believe that this (interface) method is implemented explicitly:
public class List<T> : IList
{
int IList.Add( object value ) {this.Add((T)value);}
}
By doing so, the Add( object ) method will by hidden. You'll only able to call it, if you cast the List<T> instance back to an IList instance.
A quick trip to reflector shows that IList.Add is implemented like this:
int IList.Add(object item)
{
ThrowHelper.IfNullAndNullsAreIllegalThenThrow<T>(item, ExceptionArgument.item);
try
{
this.Add((T) item);
}
catch (InvalidCastException)
{
ThrowHelper.ThrowWrongValueTypeArgumentException(item, typeof(T));
}
return (this.Count - 1);
}
In other words, the implementation casts it to T to make it work and fails it you pass a non T compatible type in.
List<T> explicitly implements IList.Add(object value) which is why it's not typically visible. You can test by doing the following:
IList list = new List<string>();
list.Add(new SqlDataReader()); // valid at compile time, will fail at runtime
It implements it explicitly, so you have to cast to IList first to use it.
List<int> l = new List<int>();
IList il = (IList)l;
il.Add(something);
You can call it be casting your list instance to the interface first:
List<int> lst = new List<int>();
((IList)lst).Add("banana");
And you'll get as nice, runtime, ArgumentException.
Frederik is right that List<T>'s implementation of IList is explicit for certain members, particularly those that pose a threat to type safety.
The implementation he suggests in his answer can't be right, of course, since it wouldn't compile.
In cases like this, the typical approach is to make a valiant effort to try to get the interface member to work, but to give up if it's impossible.
Note that the IList.Add method is defined to return:
The position into which the new
element was inserted, or -1 to
indicate that the item was not
inserted into the collection.
So in fact, a full implementation is possible:
int IList.Add(object value)
{
if (value is T)
{
Add((T)value);
return Count - 1;
}
return -1;
}
This is just a guess, of course. (If you really want to know for sure, you can always use Reflector.) It may be slightly different; for example it could throw a NotSupportedException, which is often done for incomplete interface implementations such as ReadOnlyCollection<T>'s implementation of IList<T>. But since the above meets the documented requirements of IList.Add, I suspect it's close to the real thing.
Is it possible to create an extension method that returns the instance that is invoking the extension method?
I would like to have an extension method for anything that inherits from ICollection<T>, returns the object. Much like how jQuery always returns the jquery object.
public static object AddItem<T>(this ICollection<T> collection, T itemToAdd)
{
collection.Add(itemToAdd);
return collection;
{
I imagine something like above, but I am not sure how to get back to the parent to the "this" object type for use of something like this:
List<int> myInts = new List<int>().AddItem(5);
EDIT: Just wanted to be clear that i was hoping for a single generic constraint solution.
If you need to return the specific type, you can use a generic constraint:
public static TCollection AddItem<TCollection, TElement>(
this TCollection collection,
TElement itemToAdd)
where TCollection : ICollection<TElement>
{
collection.Add(itemToAdd);
return collection;
}
I tested this and it works in VS2010.
Update (regarding jQuery):
jQuery chaining works very well because JavaScript uses dynamic typing. C# 4.0 supports dynamic, so you can do this:
public static dynamic AddItem<T>(this ICollection<T> collection, T itemToAdd)
{
collection.Add(itemToAdd);
return collection;
}
However, I do recommend the generic constraint version, since it is more type-safe, more efficient, and allows IntelliSense on the returned type. In more complex scenarios, generic constraints aren't always capable of expressing what you need; in those cases, dynamic can be used (though it won't bind to additional extension methods, so it doesn't work well with chaining).
While I don't have VS open to try this, something along these lines should work:
public static TCollection AddItem<TCollection, TItem>(TCollection collection,
TItem itemToAdd)
where TCollection : ICollection<TItem>
{
collection.Add(itemToAdd);
return collection;
}
You seem to have 2 conflicting goals, and it comes down to what do you want your extension method to return:
The instance that invoked the extension method (the collection)
OR the item that was added to the collection
From your example usage, quoted here:
List<int> myInts = new List<int>().AddItem(5);
You make it look like you want to return the collection. In any case, that assignment still won't work without a cast, since your extension method would need to have a return type of ICollection, like this:
public static ICollection<T> AddItem<T>(this ICollection<T> collection, T itemToAdd)
{
collection.Add(itemToAdd);
return collection;
}
That would allow you to do this:
List<int> myList = (List<int>) new List<int>().AddItem(5);
Now if you'd rather return the object that was added, you still shouldn't have a return type of object. You should take advantage of your generic type parameter, and return T, like this:
public static T AddItem<T>(this ICollection<T> collection, T itemToAdd)
{
collection.Add(itemToAdd);
return itemToAdd;
}
However, if you're returning the item that was added, you won't be able to chain like this:
List<int> myList = (List<int>) new List<int>().AddItem(5);
, since the return type of AddItem(5) is not ICollection, but it's T (int, in this case). You can still chain though, just off of the value added, like this:
List<int> myList = new List<int>();
myList.AddItem(5).DoSomethingWithMyInt(); // Not very useful in this case
It seems like the first scenario is more useful (returning the collection), because it does allow you chain, right off of the initial assignment statement. Here's a larger example of that:
List<int> myList = (List<int>) new List<int>().AddItem(1).AddItem(2);
Or, if you don't want to cast, you can call ToList() on the ICollection that comes back:
List<int> myList = new List<int>().AddItem(1).AddItem(2).ToList();
EDIT: Just wanted to be clear that i was hoping for a single generic constraint solution.
In this case you're out of luck because return type conversions can be covariant, but not contravariant (i.e. you cannot implicitly convert from ICollection<T> to List<T>), so without a generic return type this cannot be done.
What's wrong with specifying 2 type parameters anyway? They can be inferred by the arguments you provide to the function so you won't even really notice them in your calling code.
Just return ICollection<T>instead of object and everything should work like you intended it.