How to .skip() . take() elements on IList? - c#

Tried with :
IList<T> list= (from ...linq...).ToList();
list = list.Skip(0).Take(10);
but seems that there aren't those functions. Any other further way to do this?

First make sure you are referencing System.Linq.
Secondly the extension methods work with a stronly typed list. so use list.OfType<object>().Skip(0).Take(10)
If you know the items in your list are of a particular type then replace object with that type.
Thirdly, Skip(0) is redundant.
Additionally your code example is trying to assign from a IEnumerable to an IList you need the ToList() on your result.
list = list.Skip(0).Take(10).ToList();

have you got System.Linq referenced?
using System.Linq;

Those are method extensions that are defined in namespace System.Linq. Be sure to reference it:
using System.Linq;

Skip and Take are extensions to IEnumerable<T>. As you're dealing with the (non-generic) IList these wont be available. However if you know what type is in your IList then this should work fine:
list.OfType<YourType>().Skip(1).Take(10)
The reason this works is that OfType<T> is an extension method on the non-generic IEnumerable (which IList inherits from) and return a generic IEnumerable<T>.
references:
OfType<T>

If you mean on a non-generic IList, you need to use Cast or OfType to obtain a generic sequence first. If you expect all the elements to be of the desired type, use Cast. If you want to ignore elements of the "wrong" type, use OfType. (I prefer Cast where possible, as I generally want to get an exception if my data isn't as expected.)
For example:
IList list = ...;
var elements = list.Cast<string>()
.Skip(10)
.Take(20);
You also need a reference to the System.Core assembly and a using directive for System.Linq.
EDIT: Now that we know you've got an IList<T>, the problem is clearer. It's not that Skip and Take aren't found, it's that they don't return an IList<T>. If you change your code to:
IEnumerable<T> list= (from ...linq...).ToList();
list = list.Skip(0).Take(10);
it should work fine.

Related

How to "Cast" IEnumerable to List<T>? [duplicate]

I was wondering if it is possible to cast an IEnumerable to a List. Is there any way to do it other than copying out each item into a list?
As already suggested, use yourEnumerable.ToList(). It enumerates through your IEnumerable, storing the contents in a new List. You aren't necessarily copying an existing list, as your IEnumerable may be generating the elements lazily.
This is exactly what the other answers are suggesting, but clearer. Here's the disassembly so you can be sure:
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
return new List<TSource>(source);
}
using System.Linq;
Use the .ToList() method. Found in the System.Linq namespace.
var yourList = yourEnumerable.ToList();
https://learn.microsoft.com/en-us/dotnet/api/system.linq?view=netcore-2.2
As others suggested, simply use the ToList() method on an enumerable object:
var myList = myEnumerable.ToList()
But, if your object implementing the IEnumerable interface doesn't have the ToList() method and you're getting an error like the following:
'IEnumerable' does not contain a definition for 'ToList'
...you're probably missing the System.Linq namespace, because the ToList() method is an extension method provided by that namespace, it's not a member of the IEnumerable interface itself.
So just add the namespace to your source file:
using System.Linq
Create a new List and pass the old IEnumerable to its initializer:
IEnumerable<int> enumerable = GetIEnumerable<T>();
List<int> list = new List<int>(enumerable);
no, you should copy, if you are sure that the reference is reference to list, you can convert like this
List<int> intsList = enumIntList as List<int>;
Another gotcha (async call)
An async call may be your problem. If you added the using System.Linq statement and you are still getting the error "does not contain a definition for 'ToList' and no accessible extension method...", look carefully for the Task keyword in your error message.
Original Call (works)
IEnumerable<MyDocument> docList = await _documentRepository.GetListAsync();
Attempt to use ToList (still not working)
So...if you are doing this and it does NOT work
List<MyDocument> docList = await _documentRepository.GetListAsync().ToList();
Use parenthesis
You are actually calling ToList on the Task<IEnumerable>! Add parenthesis around your await call like this
List<MyDocument> docList = (await _documentRepository.GetListAsync()).ToList();

Generic method for both IEnumerable<T> and IQueryable<T>

I was trying to make a generic method for paging both IEnuemrable<T> and IQueryable<T>
Like this:
public T Paginate<T, TS>(T list) where T : IEnumerable<TS>
{
CheckValidityAndClamp();
return (T)(list.Skip(Page*PageSize).Take(PageSize));
}
When I passed in a List<int> instance it compiles fine.
But when run it gives a cast exception:
System.InvalidCastException : An object of type '<TakeIterator>d__3a`1[System.Int32]' can not be converted to the type 'System.Collections.Generic.List`1[System.Int32]'.
Why is that? A List<int> implements IEnumerable<int> so why the cast exception?
You're not returning a list. Take is implemented with an iterator block, which means that the actual type is a type with no compile time identifier (which is why it looks so weird) and it implements IEnumerable. It is not a List, which you're trying to cast it to.
On top of that, your method can't actually work for any IQueryable objects. It's calling the implementation of Skip that accepts an IEnumerable (because that's what the generic constraint tells the compiler it must implement) so if it were an IQueryable (even if you resolved the messy cast issue) you wouldn't be using the query provider to translate the Skip call. You need to have two overloads here, one for IQueryable and one for IEnumerable; this is pretty much inherent to the problem given that there are two Skip and Take methods that you need to call, one for each of IEnumerable and IQueryable.
To expand on Servy's (correct) answer - another issue is that Skip and Take are extension methods, which is syntactic sugar for calling static methods. Since static methods are bound at compile time, the best information that the compiler has is that T is an IEnumerable<TS>, so the compiler binds Skip and Take to the static methods of Enumerable. There's no way to dynamically bind static methods at run-time. That is why there are two different classes for the extension methods on IEnumerable and IQueryable (Enumerable and Queryable)
You need two overloads.
You get this as you cannot cast the IEnumerable to List (This is why LINQ has .ToList() extension). I think what you want is something like this:
public IEnumerable<T> Paginate<T>(IEnumerable<T> list)
{
return list.Skip(Page * PageSize).Take(PageSize);
}
Which will work with any source that implements IEnumerable (List, T[], IQueryable)
You can then call it like this:
IEnumerable<int> list = someQueryResult;
IEnumerable<int> page = class.Paginate<int>(list);
As pointed out in other answers. IQueryable has it's own set of extension methods. So all though this will work, the paging will not be done as the data-source, as it will use the IEnumerable extensions

How to know which type to use when use foreach on an IEnumerable type?

I have an object which implements IEnumerable interface. In C#, I can use foreach to iterate all its element. However I am wondering how to determine the type in the foreach loop?
If you have an old style IEnumerable (not IEnumerable<T>) you can usually call .Cast<T> or .OfType<T> to get a strongly typed one to .ForEach<T> over...
If you don't know T then you can call Debug.Write(item.GetType())
If you are using only IEnumerable you have to use object. If you know the real type then you can cast that object.
You can also use the generic IEnumberable and then you won't need to do the cast.
Why don't you try var?
foreach(var item in myEnumerable)
{
...
}
Without having the generic variant of IEumerable there is no nice way of knowing.
You could use the is operator to check first item in enumerable along with different foreach loops but I wouldn't recomend it.
If you are using the non-generic IEnumerable you cannot infer the type of items returned through the interface at compile-time. If you know enough about the object, you may know it only contains a specific type, which means you can (with relative safety) construct a foreach loop with the known type. For example, if you know it only returns strings, you can iterate over the object like so:
foreach(string s in myObject)
{
// Do some operation.
}
Unfortunately, you can return any item from a non-generic IEnumerable. If the IEnumerable returns a float, you will receive an InvalidCastException on the first line.
Worse still, there's nothing to prevent the elements being a variety of types within the same sequence. The object could legally return the following types within one foreach loop.
string
int
float
DateTime
If you don't know from the object's documentation, the only other certain way to know the type of any one item in the loop is to check at runtime.
These are the reasons why it's always preferable to use the generic IEnumerable<T> over IEnumerable when you know your object will only really return one type of value.

Why doesn't the Controls collection provide all of the IEnumerable methods?

I'm not for sure how the ControlCollection of ASP.Net works, so maybe someone can shed some light on this for me.
I recently discovered the magic that is extension methods and Linq. Well, I was very sad to find that this isn't valid syntax
var c=Controls.Where(x => x.ID=="Some ID").SingleOrDefault();
However from what I can tell, Controls does implement the IEnumerable interface which provides such methods, so what gives? Why doesn't that just work? I have found a decent work around for this issue at least:
var list = (IEnumerable<Control>)Controls;
var this_item = list.Where(x => x.ID == "Some ID").SingleOrDefault();
No, IEnumerable doesn't have many extension methods on it: IEnumerable<T> does. They are two separate interfaces, although IEnumerable<T> extends IEnumerable.
The normal LINQ ways of converting are to use the Cast<T>() and OfType<T>() extension methods which do extend the nongeneric interface:
IEnumerable<TextBox> textBoxes = Controls.OfType<TextBox>();
IEnumerable<Control> controls = Controls.Cast<Control>();
The difference between the two is that OfType will just skip any items which aren't of the required type; Cast will throw an exception instead.
Once you've got references to the generic IEnumerable<T> type, all the rest of the LINQ methods are available.
This is just because the ControlCollection class came around before generics; so it implements IEnumerable but not IEnumerable<Control>.
Fortunately, there does exist a LINQ extension method on the IEnumerable interface that allows you to generate an IEnumerable<T> through casting: Cast<T>. Which means you can always just do this:
var c = Controls.Cast<Control>().Where(x => x.ID == "Some ID").SingleOrDefault();
In addition to the answers provided by Jon Skeet and Dan Tao, you can use query expression syntax by explicitly providing the type.
Control myControl = (from Control control in this.Controls
where control.ID == "Some ID"
select control).SingleOrDefault();
Linq utilized Generic Collections. ControlsCollection implements IEnumerable not IEnumberable<T>
If you notice this will not work
((IEnumerable)page.Controls).Where(...
However, this does
((IEnumerable<Control>)page.Controls).Where(...
You can either cast to Generic IEnumerable<T> or access an extension method that does, like so:
page.Controls.OfType<Control>().Where(c => c.ID == "Some ID").FirstOrDefault();

Extension Method ConvertAll

What is the proper use of ConverAll ? Will it convert one type to another type?
like
List<int> intList = new List<int>();
intList.Add(10);
intList.Add(20);
intList.Add(30);
intList.Add(33);
var query= intList.ConvertAll(x=>(double)x);
for this i can use cast or OfType<>.
ConvertAll isn't an extension method, it's a real method on List<T> itself.
It returns a new list containing the converted elements. So in your example, the query variable isn't actually a query, it's a List<double>.
Cast and OfType are extension methods that operate on IEnumerable and return an IEnumerable<T>. However they're not suitable for your stated purpose: Cast can convert reference types but cannot convert value types, only unbox them. OfType doesn't perform any conversion, it just returns any elements that are already of the specified type.
ConvertAll will just call your delegate/anonymous method for each element of the list. What this does is entirely up to you.
In the example code you posted, it will attempt to cast each element to a double and return that, which means you'll get a List<Double> in return.
You should not use OfType<T>, since this will filter the elements based on the type, and will only return a different type than the original if it is type compatible due to inheritance or interface implementation.
In other words, .OfType<Double> will return no elements, since none of the ints are also doubles.
ConvertAll is a projection operator and maps most closely to LINQ's Select. LINQ's Cast is a specific projection operator and represents doing what you did [via projection] - or it would (as pointed out in Luke's answer [and comment], which I +1'd) if you weren't converting to a value type.
In general, LINQ has a more complete and well-thought-through set of operators, which makes older stuff like ConvertAll look a bit silly at times [like this]. (or #stoopid :D).
to my knowledge, OfType<T> will only return the elements in the collection that are of the specified type T.
ConvertAll allows you to convert the elements to another type.

Categories

Resources