A
Anders Borum
Hello
I'm developing an API with a number of concrete collections that inherit
from an abstract collection hierarchy. Each inheritance level provides an
implementation of IEnumerable<T>, thus allowing the developer to take full
advantage of the LINQ extensions without having to start with a cast
operation to a concrete type that matches the collection.
I was surprised that the C# compiler was unable to resolve the type of the
range variable when writing LINQ queries against a collection that hides an
inherited IEnumerable<T>. Consider the following example (just to be clear -
I'm fully aware that it is possible to write the following using a generic
collection instead, but please follow me);
public class Animal {}
public class Tiger : Animal {}
public abstract class AnimalCollection : IEnumerable<Animal>
{
public IEnumerator<Animal> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
public class TigerCollection : AnimalCollection, IEnumerable<Tiger>
{
public new IEnumerator<Tiger> GetEnumerator()
{
throw new NotImplementedException();
}
}
public void ProcessAnimals()
{
AnimalCollection animals = new TigerCollection();
TigerCollection tigers = new TigerCollection();
// works
var a1 = from a in animals select a;
// fails (requires explicit specification of t as Tiger)
var t1 = from t in tigers select t;
// works when specifying Tiger explicitly
var t1 = from Tiger t in tigers select t;
}
Error 1 Could not find an implementation of the query pattern for source
type 'TigerCollection'. 'Select' not found. Consider explicitly specifying
the type of the range variable 't'.
We were just wondering why the C# compiler is unable to resolve the type
Tiger from the TigerCollection (now that it explicit implements
IEnumerable<Tiger>.
I'm developing an API with a number of concrete collections that inherit
from an abstract collection hierarchy. Each inheritance level provides an
implementation of IEnumerable<T>, thus allowing the developer to take full
advantage of the LINQ extensions without having to start with a cast
operation to a concrete type that matches the collection.
I was surprised that the C# compiler was unable to resolve the type of the
range variable when writing LINQ queries against a collection that hides an
inherited IEnumerable<T>. Consider the following example (just to be clear -
I'm fully aware that it is possible to write the following using a generic
collection instead, but please follow me);
public class Animal {}
public class Tiger : Animal {}
public abstract class AnimalCollection : IEnumerable<Animal>
{
public IEnumerator<Animal> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
public class TigerCollection : AnimalCollection, IEnumerable<Tiger>
{
public new IEnumerator<Tiger> GetEnumerator()
{
throw new NotImplementedException();
}
}
public void ProcessAnimals()
{
AnimalCollection animals = new TigerCollection();
TigerCollection tigers = new TigerCollection();
// works
var a1 = from a in animals select a;
// fails (requires explicit specification of t as Tiger)
var t1 = from t in tigers select t;
// works when specifying Tiger explicitly
var t1 = from Tiger t in tigers select t;
}
Error 1 Could not find an implementation of the query pattern for source
type 'TigerCollection'. 'Select' not found. Consider explicitly specifying
the type of the range variable 't'.
We were just wondering why the C# compiler is unable to resolve the type
Tiger from the TigerCollection (now that it explicit implements
IEnumerable<Tiger>.