I have this method, it selects data in a particular range (pageIndex and pageSize)
public PagedList(IQueryable<T> source, int pageIndex, int pageSize)
{
this.AddRange(source.Skip(pageIndex * pageSize).Take(pageSize).ToList());
}
I want to create an overloading method which selects all data, so, here's my code
public PagedList(IQueryable<T> source)
{
//this.AddRange(source.Select(x => new T()).ToList()); (1)
this.AddRange(source.AsQueryable().ToList()); (2)
}
Firstly, I tried (1), but it didn't accept T. Then I tried (2), and it's recommended that I should make parameter type INumerable instead of IQueryable. What is the solution to select all data in this case?
Thanks
You can do it simply like this:
public PagedList(IEnumerable<T> source)
{
this.AddRange(source);
}
IEnumerable<T> as parameter type instead of IQueryable<T>, because you don't use any features specific to IQueryable<T>.
No AsQueryable because you simply want all data
No ToList as List<T>.AddRange internally already performs a copy. With ToList there would be two copy operations going on.
What would be wrong with:
public PagedList(IQueryable<T> source)
{
this.AddRange(source.ToList());
}
Making something Queryable just to then make it a list seems weird. Especially given that source is already Queryable.
Both IEnumerable and IQueryable are fine, it depends only on what you actualy need.
For a better case sudy you can read this.
What is the difference between IQueryable<T> and IEnumerable<T>?
Related
I want to get data from context in a class out of my aspx code behind,as this:
MyClass.GetIt().Skip((page - 1) * perPage).Take(perPage);
but I don't know which of these methods should I use that in my paging not all rows put in memory?
1.
public static IQueryable<T> GetIt()
{
return context.MyObject.Where(i=>i.Type==1);
}
2.
public static IEnumerable<T> GetIt()
{
return context.MyObject.Where(i=>i.Type==1);
}
The first one - IQueryable<T>.
Returning IEnumerable would cause taking all matching elements from DB into memory and would perform Skip and Take as LINQ to object query.
I have a List<Person> and instead want to convert them for simple processing to a List<string>, doing the following:
List<Person> persons = GetPersonsBySeatOrder();
List<string> seatNames = persons.Select(x => x.Name).ToList();
Console.WriteLine("First in line: {0}", seatNames[0]);
Is the .Select() statement on a LINQ to Objects object guaranteed to not change the order of the list members? Assuming no explicit distinct/grouping/ordering is added
Also, if an arbitrary .Where() clause is used first, is it still guaranteed to keep the relative order, or does it sometimes use non-iterative filtering?
As Fermin commented above, this is essentially a duplicate question. I failed on selecting the correct keywords to search stackoverflow
Preserving order with LINQ
It depends on the underlying collection type more than anything. You could get inconsistent ordering from a HashSet, but a List is safe. Even if the ordering you want is provided implicitly, it's better to define an explicit ordering if you need it though. It looks like you're doing that judging by the method names.
In current .Net implementation it use such code. But there are no guarantee that this implementation will be in future.
private static IEnumerable<TResult> SelectIterator<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
{
int index = -1;
foreach (TSource source1 in source)
{
checked { ++index; }
yield return selector(source1, index);
}
}
Yes, Linq Select is guaranteed to return all its results in the order of the enumeration it is passed. Like most Linq functions, it is fully specified what it does. Barring handling of errors, this might as well be the code for Select:
IEnumerable<Y> Select<X, Y>(this IEnumerable<X> input, Func<X, Y> transform)
{
foreach (var x in input)
yield return transform(x);
}
But as Samantha Branham pointed out, the underlying collection might not have an intrinsic order. I've seen hashtables that rearrange themselves on read.
I am reading C# AsEnumerable:
"The IEnumerable interface is a generic interface. This means it
defines a template that types can implement for looping. The
AsEnumerable method, a generic method, allows you to cast a specific
type to its IEnumerable equivalent"
Further on, a code example:
using System;
using System.Linq;
class Program
{
static void Main()
{
// Create an array type.
int[] array = new int[2];
array[0] = 5;
array[1] = 6;
// Call AsEnumerable method.
var query = array.AsEnumerable();
foreach (var element in query)
{
Console.WriteLine(element);
}
}
}
Sounds like I need to convert an array to an IEnumerable type object to use looping (foreach?).
But applying foreach directly to an array yields exactly the same results:
using System;
//using System.Linq;
class Program
{
static void Main()
{
// Create an array type.
int[] array = new int[2];
array[0] = 5;
array[1] = 6;
// Call AsEnumerable method.
//var query = array.AsEnumerable();
foreach (var element in array)
{
Console.WriteLine(element);
}
}
}
So, the entire webpage with an explanation of AsEnumerable() method is void for me.
What did I miss?
The example is bad and it should feel bad. Here is a better, if somewhat contrived example:
If I have an extension method defined on the, let's say, the array type, like this:
public static class ArrayExtension {
public static bool Any<T>(this T[] source, Func<T,bool> predicate)
{
Console.WriteLine("Undesirable side behaviour");
SomeResourceIntensiveOperation();
Console.WriteLine("Inefficient implementation");
return source.Where(predicate).Count() != 0;
}
}
and I do
int[] nums = new []{1,2,3,4,5};
nums.Any(n=> n % 2 == 0);
If will execute and run my implementation, even if i do not need that. By doing
nums.AsEnumerable().Any(n => n % 2 == 0);
it will call the default implementation.
The real benefit is when you are using IQueryable implementations (e.g. LINQ-to-SQL), because, for example, the Where for IEnumerable is defined as
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
but the IQueryable.Where is defined with
public static IQueryable<TSource> Where<TSource>(
this IQueryable<TSource> source,
Expression<Func<TSource, bool>> predicate)
When the IQueryable behaviour is undesireable one can call the AsEnumerable() to force the IEnumerable behaviour.
From MSDN
The AsEnumerable<TSource>(IEnumerable<TSource>) method has no effect other than to change the compile-time type of source from a type that implements IEnumerable<T> to IEnumerable<T> itself.
AsEnumerable<TSource>(IEnumerable<TSource>) can be used to choose between query implementations when a sequence implements IEnumerable<T> but also has a different set of public query methods available. For example, given a generic class Table that implements IEnumerable<T> and has its own methods such as Where, Select, and SelectMany, a call to Where would invoke the public Where method of Table. A Table type that represents a database table could have a Where method that takes the predicate argument as an expression tree and converts the tree to SQL for remote execution. If remote execution is not desired, for example because the predicate invokes a local method, the AsEnumerable<TSource> method can be used to hide the custom methods and instead make the standard query operators available.
It makes no sense in YOUR example logically (i.e. from array). I would assume the first code has been written by a beginner, or - more down - an example.
It does make sense in the sense of LINQ as "AsEnumerable" triggers the evaluation of the query and depending on the ORM That can mean freeing up a database connection for a reuse within the loop.
THAT SAID:
You read too much into examples. In an example, code is there not to be "good" but to show a point. In this case it may make sense to DEMONSTRATE the use of AsEnumerable - and an Array is the fastest enumerable object to initialize (in terms of lines of code), to keep the example short. Examples point out specific things, they are not "good code" for anything.
This is just another example. Suppose I have this method:
static void MyMeth(int[] numbers)
{
var query = numbers.Reverse(); // works fine, calls Linq extension
// ... use query ...
}
Then I decide to change numbers into a List<int> instead, and try:
static void MyMeth(List<int> numbers)
{
var query = numbers.Reverse(); // will not compile!
// ... use query ...
}
The problem here is that the List<> class has another method which is also called Reverse. That method returns void (because it modifies the original List<> in-place). I don't want that. One solution would be to upcast numbers explicitly:
static void MyMeth(List<int> numbers)
{
var query = ((IEnumerable<int>)numbers).Reverse(); // fine; Linq
// ... use query ...
}
But another solution would be AsEnumerable<>, so:
static void MyMeth(List<int> numbers)
{
var query = numbers.AsEnumerable().Reverse(); // fine too; Linq
// ... use query ...
}
Conclusion: The purpose of AsEnumerable method is to "forget" methods on the specialized type that happen to "hide" the extension methods on the general type IEnumerable<>. This can be incredibly important in the case where the "specialized" type is/inherits IQueryable<> where there are (extension) methods Where, Select and so on which do something different (namely ingest the lambda as an expression tree, analyze it, and "translate" it into SQL or something) than do Where, Select etc. on IEnumerable<>.
Is there a method in Linq that does the same as ElementAt except it returns an IEnumerable<T> with a single element, rather than the actual element? Isn't there some SelectRange(startIndex, endIndex) method I could use and just pass the same index twice?
The simplest way would be to use
source.Skip(count).Take(1)
or more generally
source.Skip(startIndex).Take(endIndex - startIndex)
(assuming an inclusive startIndex but exclusive endIndex).
Ah.. it's called GetRange(index, count). My bad. Just found it :)
Jon Skeet's technique is a great way to do it. I would however suggest a possible optimization that is based on an implementation detail in Enumerable.Skip: it does not currently appear to take advantage of indexers on IList or IList<T>. Fortunately, Enumerable.ElementAt does.
So an alternate solution would be:
var itemAsSequence = new[] { source.ElementAt(index) };
Do note that this will execute eagerly. If you want deferred execution semantics similar to Jon's answer, you could do something like:
public static IEnumerable<T> ElementAtAsSequence<T>
(this IEnumerable<T> source, int index)
{
// if you need argument validation, you need another level of indirection
yield return source.ElementAt(index);
}
...
var itemAsSequence = source.ElementAtAsSequence(index);
I should point out that since this relies on an implementation detail, future improvements in LINQ to Objects could make this optimization redundant.
write an extension method
public static IEnumerable<T> ToMyEnumerable<T>(this T input)
{
var enumerbale = new[] { input };
return enumerbale;
}
source.First( p => p.ID == value).ToMyEnumerable<T>()
which is O(n)
If I have two sequences and I want to process them both together, I can union them and away we go.
Now lets say I have a single item I want to process between the two sequencs. I can get it in by creating an array with a single item, but is there a neater way? i.e.
var top = new string[] { "Crusty bread", "Mayonnaise" };
string filling = "BTL";
var bottom = new string[] { "Mayonnaise", "Crusty bread" };
// Will not compile, filling is a string, therefore is not Enumerable
//var sandwich = top.Union(filling).Union(bottom);
// Compiles and works, but feels grungy (looks like it might be smelly)
var sandwich = top.Union(new string[]{filling}).Union(bottom);
foreach (var item in sandwich)
Process(item);
Is there an approved way of doing this, or is this the approved way?
Thanks
One option is to overload it yourself:
public static IEnumerable<T> Union<T>(this IEnumerable<T> source, T item)
{
return source.Union(Enumerable.Repeat(item, 1));
}
That's what we did with Concat in MoreLINQ.
The new way of doing this, supported in .NET Core and .NET Framework from version 4.7.1, is using the Append extension method.
This will make your code as easy and elegant as
var sandwich = top.Append(filling).Union(bottom);
Consider using even more flexible approach:
public static IEnumerable<T> Union<T>(this IEnumerable<T> source, params T[] items)
{
return source.Union((IEnumerable<T>)items);
}
Works for single as well as multiple items.
You may also accept null source values:
public static IEnumerable<T> Union<T>(this IEnumerable<T> source, params T[] items)
{
return source != null ? source.Union((IEnumerable<T>)items) : items;
}
I tend to have the following somewhere in my code:
public static IEnumerable<T> EmitFromEnum<T>(this T item)
{
yield return item;
}
While it's not as neat to call col.Union(obj.EmitFromEnum()); as col.Union(obj) it does mean that this single extension method covers all other cases I might want such a single-item enumeration.
Update: With .NET Core you can now use .Append() or .Prepend() to add a single element to an enumerable. The implementation is optimised to avoid generating too many IEnumerator implementations behind the scenes.