I have some custom list which is based on IEnumerable<T>. Now I want to overload the constructor and do some custom stuff with the initial list I get.
//Constructor
public CustomList(IEnumerable<T> collection) : base(collection)
{
//do some stuff with the collection e.g. iterate
foreach(T obj in collection)
{
//do some stuff with obj
}
}
Is it even possible to do so? Because IEnumerable can only be enumerated once at base(collection), but the loop will fail, I guess.
EDIT:
since it is not completely clear for everyone: My base class is IEnumerable<T> and IEnumerable can only be enumerated once in my case.
Assuming your base class is List<T>, then the base constructor adds all the items to the current object. So you could do the following as often as you want:
foreach (T obj in this) { }
But I've heard it's a bad idea to inherit from List<T>, that you should implement IList<T> instead, even if it is just a wrapper around List<T>. I just can't remember why that is.
Related
Like I see, most IEnumerable extensions eats IEnumerable and then vomits also IEnumerable. Is it possible to make an extension method, which can eat any IEnumerable (like List) and then return the same type - List?
For example, I want to iterate over collection, if something is wrong, I will throw exception, but if all is OK, I need to return same instance (same type).
You need to use two generic arguments:
public static TEnumerable Foo<TEnumerable, TItem>(this TEnumerable sequence)
where TEnumerable: IEnumerable<TItem>
{
return sequence;
}
Note that as a result of this change you're not going to be able to infer the generic arguments when invoking this method; you're going to have to specify them explicitly.
I don't see how doing this could be beneficial, but you can solve the generics part of the problem like this:
public static TEnumerable MyExtensionMethod<T, TEnumerable>(this TEnumerable enumerable)
where TEnumerable : IEnumerable<T>
{
...
}
However, you may find it difficult to actually implement such a thing because there is no generic way to create the TEnumerable you want to return.
For example, I want to iterate over collection, if something is wrong, I will throw exception, but if all is OK, I need to return same instance (same type).
Does the following extension method not accomplish what you really want? I don't understand why you want to return the same instance.
public static void Consume<T>(this IEnumerable<T> enumerable)
{
foreach (var item in enumerable)
{
// Do nothing
}
}
I had to implement 2 interface same time with different generic parameter as below. I get confused enough about it. I had no idea which one of them iterate itself in foreach. Now i understand first one is implicitly choosen.
I have tried new BarList().GetEnumerator() but i can not specify type parameter on method level.
Only solution i have found it that casting it to interface like(new BarList() as IEnumerable<string>)
After confusing about it enough. I just wanted to know that this design is not really good idea ? I have to avoid to implement same generic interface one more time ?
class Program
{
static void Main(string[] args)
{
foreach (var item in new BarList())
{
}
}
}
class BarList: IEnumerable<string>, IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
throw new NotImplementedException();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator<string> IEnumerable<string>.GetEnumerator()
{
throw new NotImplementedException();
}
}
Edit:
Let me explain why i am going in this way.
I had to Implement IPagedList<T> interface which is inherited from IList<T>. I wanted to write extension method which convert it to My view model. like below
GetAll().ToPagedList(pageindex);//which is returning IPagedList Then i wanted to use it like below;
GetAll().ToPagedList(pageindex).ToViewModel<T,TViewModel>();
For achieve this I tried to return IPagedList<ViewModel> by that extension method.In that case I have to implement IPagedList 2 times with different parameter. But this strategy made confusing things. This is reason of it.
This seems a bit confusing. Why not make it explicit what is happening by adding the enumerators as properties rather than implementing them on the class. For example,
class ProductCollection
{
public IEnumerable<int> EnumerateTheInts { get { //code to produce enumerator }}
public IEnumerable<string> EnumerateTheStringss { get { //code to produce enumerator }}
}
It isn't always bad to implement an open generic interface twice on an object. For example, IHandle could be implemented by a class which can handle two types of T. However, I would find it confusing to implement IEnumerable twice, because you might not enumerate the type you expect in a for-each or in LINQ. Same reasoning for implementing more than one indexer incidentally. The type of your indexer will determine your result, which I can testify to being extremely confusing!
The compiler is picking the IEnumerator<int> GetEnumerator method by following the rules in 8.8.4 of the C# language specification which first looks for an accessible GetEnumerator() method on the BarList type. The only one of those which is available is the one returning IEnumerator<int>.
If you had made that method use explicit interface implementation as well, then it would have gone onto the later stages of section 8.8.4, which states that if there is more than one type T such that there is an implicit conversion from the expression type (BarList here) to IEnumerable<T> then an error is produced.
I would say this is a confusing design - I would probably add properties or methods to retrieve appropriate "views" on the data.
I'd avoid it. However, it depends on your usage.
It will be okay if you just wanted to pass the instance into a function that expects a IEnumerable<string> parameter explicitely:
you won't have to cast
the function won't even 'see' the other interfaces implemented, so there isn't any confusion.
YMMV
Your current design is confusing. While you have not provided any information about the nature of the collection itself, from the name, I can assume you are supposed to iterate over a bunch of products. Perhaps, you should simply have a class of type Product with a string property and an int property and simply return an IEnumerable<Product> instead.
This way, with LINQ extension methods, you can compose the IEnumerable<T> object you actually mean with:
collection.Select(product => product.IntegerProperty)
collection.Select(product => product.StringProperty)
Of course, you can provide helper methods inside the object as well:
class ProductCollection : IEnumerable<Product> {
public IEnumerable<Product> GetEnumerator() {
// ... return Product objects here.
}
public IEnumerable<int> AsIntegerCollection() {
// yield the integer collection here
}
public IEnumerable<string> AsStringCollection() {
// yield the string collection here
}
}
What are these collections of string and ints? I suppose they mean something in relation with the Product (for example Name, Id, etc...) so I would rather do something like this:
class ProductCollection : IEnumerable<Product>
{
public IEnumerator<Product> GetEnumerator()
{
...
}
public IEnumerator<string> ProductNames // a helper to enumerate product names
{
...
}
public IEnumerator<int> ProductIds // a helper to enumerate product ids
{
...
}
}
OK.
I have a class MyClass and another class that is based on List. Let's call it MyCollection.
Now when someone types:
MyCollection coll = new MyCollection();
...
coll.Find(...)
They are acting on the entire collection. I want to apply some filtering - behind the scenes - so that if they write the above code, what actually executes is something like...
coll.Where(x=>x.CanSeeThis).Find(...)
What do I need to write in the definition of the MyCollection class to make this work?
Can I make this work?
You probably want to write a wrapper class that implements IList or ICollection, using a regular List internally. This wrapper class would then proxy all method calls to the internal list, applying the filter as required.
You´ve already mentioned you´ve got your own collection, probably derived from List right?
Then you´ll need to create your own method for finding:
public class MyList<T> : System.Collections.Generic.List<T>
{
public IEnumerable<T> MyFind(Predicate<T> match)
{
return this.Where(x => x.CanSeeThis).ToList().Find(match);
}
}
This unfortunatly is needed because you cannot override the Find method on List directly. You can however use the 'new' keyword to specify that If you´ve got a reference to the instance of MyList it will use that implementation of find, like below:
public new IEnumerable<T> Find(Predicate<T> match)
{
return this.Where(x => x.CanSeeThis).ToList().Find(match);
}
However the above example will yield:
MyCollection<int> collection = new ...
collection.Find(myPredicate); // <= Will use YOUR Find-method
List<int> baseTypeCollection = collection; // The above instantiated
baseTypeCollection.Find(myPredicate); // Will use List<T>.Find!
So it´s better you make you´re own method.
If I have these two classes:
class A {}
class B : A {}
and I make a List<A> but I want to add a List<B> to it by calling List<A>.AddRange(List<B>) but the compiler refuses:
Argument '1': cannot convert from 'System.Collections.Generic.List<A>'
to 'System.Collections.Generic.IEnumerable<B>
which I completely understand because IEnumerable<B> does not inherit from IEnumerable<A>, its generic type has the inheritance.
My solution is to enumerate through List<B> and individually add items because List<A>.Add(A item) will work with B items:
foreach(B item in listOfBItems)
{
listOfAItems.Add(item);
}
However, that's rather non-expressive because what I want is just AddRange.
I could use
List<B>.ConvertAll<A>(delegate(B item) {return (A)item;});
but that's unnecessarily convoluted and a misnomer because I'm not converting, I'm casting .
Question: If I were to write my own List-like collection what method would I add to it that would allow me to copy a collection of B's into a collection of A's as a one-liner akin to List<A>.AddRange(List<B>) and retain maximum type-safety. (And by maximum I mean that the argument is both a collection and type inhertance checking.)
Indeed, generic types are not variant right now. In C# 4.0, IEnumerable<B> will be convertible to IEnumerable<A> if B is convertible to A via a reference conversion. For some details on the design of this feature, see:
http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx
This does unfortnuately not work because generics in .net do not (yet) support covariance.
You can make a small helper method or class to overcome this issue however.
If you implement your own list class, you can add covariance using an additional generic parameter:
class MyList<T> {
void AddRange<U>(IEnumerable<U> items) where U: T {
foreach (U item in items) {
Add(item);
}
}
}
Can't you just do:
listOfAItems.AddRange(listOfBItems.Cast<A>());
I was able to achieve this using LINQ...
listOfAItems.AddRange(listOfBItems.Cast<A>());
In case you find yourself in a situation where generic types are not variant, the following extension method can make your life easier:
public static void AddRange<TList,TOther>(this List<TList> list, IEnumerable<TOther> collection) where TOther: TList {
foreach(TOther e in collection) {
list.Add(e);
}
}
Instead of having to derive from List<T> or having this method in some utility class, using it as an extension method simplifies usage. You can also profit from inference, so this formerly invalid call will become valid without any modification:
List<Animal> animals;
List<Dog> dogs;
animals.AddRange(dogs);
The only thing I can come up with is this
public class MyList<T> : List<T>
{
public void AddRange<Tother>(IEnumerable<Tother> col)
where Tother: T
{
foreach (Tother item in col)
{
this.Add(item);
}
}
}
Calling it means doing MyList<A>.AddRange<B>(MyList<B>). This fails if the argument is not enumerable or if the type inheritance doesn't work out so it satisfies my question's maximum type safety requirement.
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(); }
}