C# List Generic Extension Method vs Non-Generic - c#

This is a simple question (I hope), there are generic and non-generic methods in collection classes like List<T> that have methods such as Where and Where<T>.
Example:
List<int> numbers = new List<int>()
{
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
};
IEnumerable<int> evens = numbers.Where((x) =>
{
return x % 2 == 0;
});
IEnumerable<int> evens2 = numbers.Where<int>((x) =>
{
return x % 2 == 0;
});
Why use one over the other (Generic or Non-Generic)?

They're the same method (documentation here). The type parameter portion after the method name (i.e. <int> in this case) is optional when the compiler is able to infer the type automatically and unambiguously from context. In this case, the method is being applied to an object implementing the interface IEnumerable<int> (i.e. the object numbers of type List<int>) from which the compiler can safely infer that the type parameter is int.
Note, also, that Where<T> is actually an extension method on the System.Linq.Enumerable class which can be applied to objects of any class implementing IEnumerable<T> such as List<T>.

Related

Please help me with Queryable.select

How can I fix this error ?
> Type arguments for method Queryable.Select<TSource>,<TResult> ....
> cannot be inferred from the usage.
> Try specifying the type arguments explicitly.
This is my code
Comments = e.Comments.AsQueryable().Select(CommentViewMode.ViewModel)
It shows the red squiggly line on 'Select'
Minnie,
The LINQ Select extension method for IQueryable takes a function as an argument. The documentation from Microsoft shows the signature and a simple example:
List<int> range =
new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// Project the square of each int value.
IEnumerable<int> squares =
range.AsQueryable().Select(x => x * x);
So the Select method expects a function that takes an argument of the same type as your queryable enumerates. In the example above, it is an int. In the code you provided it will be the type of one of your Comments elements. I expect you need to write your select like this:
var something = e.Comments.AsQueryable().Select(x => x.SomePropertyOfYourCommentClass)

Why compiler does not allow us to use `var` instead of `generic type`?

In the example code below Generic Type is used in writing a Reverse function that reverses an array of any type:
public T[] Reverse<T>(T[] array)
{
var result = new T[array.Length];
int j=0;
for(int i=array.Length; i>= 0; i--)
{
result[j] = array[i];
j++;
}
return result;
}
However, I could write the same code like below by using var type:
public var[] Reverse(var[] array)
{
var result = new var[array.Length];
int j=0;
for(int i=array.Length; i>= 0; i--)
{
result[j] = array[i];
j++;
}
return result;
}
However, the compiler does not accept the latter. I want know to the difference between Generic type and var?
It doesn't compile, so it doesn't work.
The use of generics and the var are very different. var means "compiler, I'm lazy, please discover for me the single exact type that I should use here, inferring it from what I'm writing after the =" (there are some cases where it is mandatory to use var instead of writing explicitly the variable type, but we will ignore them) ... So for example
var foo = "Hello";
The foo variable type is string, because the compiler can infer it by looking at the type of the expression after the assignment =. The var is totally replaced by the "correct" type in the compiled program.
So it would be equivalent to writing:
string foo = "Hello";
Generics instead are a way to make a method/class able to adapt to different types that are used in calling/creating them. In this instance the caller could
int[] foo1 = Reverse(new int[] { 1, 2, 3, 4, 5);
or
long[] bar1 = Reverse(new long[] { 1, 2, 3, 4, 5);
The compiler (because generics are resolved at compile time) will infer the type T (int or long) from the parameters used and will write it somewhere (in the compiled file). The runtime then will see this and create two different specialized versions of Reverse (one for int and one for long). But in this case T is an "openness" to the various possible types of parameters. In the case of var, there is a single possible type that the variable can be. So in the compiled file there is a Reverse<T> compiled method, while at runtime there are a Reverse<int> version of the method and a Reverse<long> version of the method (and if necessary the runtime will create other versions of the method).
Using var as a parameter wouldn't have any meaning, and it would be a poorer syntax than the generics one, where the list of used generics are put somewhere (between the method name and the ( in this case) and you can have multiple generic types, like
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
(that is the LINQ Select) where there are two generic parameters TSource and TResult. With your syntax you wouldn't be able to differentiate between the two generic parameters (there is a single var keyword), and you couldn't use var as is currently used (compiler, I'm lazy, please discover for the the type of this local variable).

Can params[] be parameters for a lambda expression? [duplicate]

This question already has answers here:
Variable parameters in C# Lambda
(5 answers)
Closed 1 year ago.
I've recently started exploring lambda expressions, and a question came to mind. Say I have a function that requires an indeterminate number of parameters. I would use the params keyword to model that variable number of parameters.
My question: can I do something similar with Lambda expressions? For example:
Func<int[], int> foo = (params numbers[]) =>
{
int result;
foreach(int number in numbers)
{
result += numbers;
}
return result;
}
If so, two sub-questions present themselves - is there a 'good' way to write such an expression, and would I even want to write an expression like this at some point?
Well, sort of.
First, instead of using Func<>, you would need to define a custom delegate:
public delegate int ParamsFunc (params int[] numbers);
Then, you could write a following lambda:
ParamsFunc sum = p => p.Sum();
And invoke it with variable number of arguments:
Console.WriteLine(sum(1, 2, 3));
Console.WriteLine(sum(1, 2, 3, 4));
Console.WriteLine(sum(1, 2, 3, 4, 5));
But to be honest, it is really much more straightforward to stick with built-in Func<> delegates.
The closest thing that I think you can get would be something like this:
Func<int[], int> foo = numbers[] =>
{
// logic...
}
var result = foo(Params.Get(1, 5, 4, 4, 36, 321, 21, 2, 0, -4));
And have:
public static class Params
{
public static T[] Get(params T[] arr)
{
return arr;
}
}
But I can't see how that beats a simple new[] {1, 5, 4, 4, ...}
There are two things here, the Func<int[], int> generic delegate on the LHS and the lambda expression on the RHS. The former is not possible, since a Func<S, T> delegate is declared like:
public delegate TResult Func<in T, out TResult>(T arg); //ie no params involved
You need your own delegate that accepts params input as shown in accepted answer.
The latter, which is what the question title is about, is not possible as well in C#, but for a reason.
The LHS of an assignment expression is a compile time thing (unless it's dynamic of course but again compiler is aware of it) and its RHS is a run time thing (unless of course in case of consts). The compiler can infer what's typed on LHS, but it gets the values on RHS only during run time, ie when the code is run. When you type this:
Func<int[], int> foo = ....
foo is always considered as Func<int[], int>. It will add a lot of complexity to compiler if it had to decipher RHS. For e.g. if what you're attempting was possible, think about this scenario:
Func<int[], int> foo = (params int[] numbers) =>
{
int result;
foreach(int number in numbers)
{
result += numbers;
}
return result;
};
//and later at some other place
foo = (int[] numbers) => 0;
//how would you call 'foo' now?
Instead when you write your own delegate that accepts params, you're telling the compiler directly (ie known from LHS).
Of the three features that parameters of a named method support, ie, out/ref, params, optional parameter, lambda expressions (or even the earlier delegate syntax) support only out/ref.

Flatten IEnumerable<IEnumerable<>>; understanding generics

I wrote this extension method (which compiles):
public static IEnumerable<J> Flatten<T, J>(this IEnumerable<T> #this)
where T : IEnumerable<J>
{
foreach (T t in #this)
foreach (J j in t)
yield return j;
}
The code below causes a compile time error (no suitable method found), why?:
IEnumerable<IEnumerable<int>> foo = new int[2][];
var bar = foo.Flatten();
If I implement the extension like below, I get no compile time error:
public static IEnumerable<J> Flatten<J>(this IEnumerable<IEnumerable<J>> #this)
{
foreach (IEnumerable<J> js in #this)
foreach (J j in js)
yield return j;
}
Edit(2): This question I consider answered, but it raised another question regarding overload resolution and type constraints. This question I put here: Why aren't type constraints part of the method signature?
First, you don't need Flatten(); that method already exists, and is called SelectMany(). You can use it like this:
IEnumerable<IEnumerable<int>> foo = new [] { new[] {1, 2}, new[] {3, 4} };
var bar = foo.SelectMany(x => x); // bar is {1, 2, 3, 4}
Second, your first attempt doesn't work because generic type inference works only based on the arguments to the method, not generic constraints associated with the method. Since there is no argument that directly uses the J generic parameter, the type inference engine can't guess what J should be, and thus doesn't think that your method is a candidate.
It's edifying to see how SelectMany() gets around this: it requires an additional Func<TSource, TResult> argument. That allows the type inference engine to determine both generic types, since they are both available based solely on the arguments provided to the method.
dlev's answer is fine; I just thought I'd add a little more information.
Specifically, I note that you are attempting to use generics to implement a sort of covariance on IEnumerable<T>. In C# 4 and above, IEnumerable<T> already is covariant.
Your second example illustrates this. If you have
List<List<int>> lists = whatever;
foreach(int x in lists.Flatten()) { ... }
then type inference will reason that List<List<int>> is convertible to IE<List<int>>, List<int> is convertible to IE<int>, and therefore, because of covariance, IE<List<int>> is convertible to IE<IE<int>>. That gives type inference something to go on; it can infer that T is int, and everything is good.
This doesn't work in C# 3. Life is a bit harder in a world without covariance but you can get by with judicious use of the Cast<T> extension method.

What is actually happening with IQueryable.Where()?

This is is returning a boolean based on whether or not there are some matching IDs.
from t in getAll
select new Result
{
...
bool DetailsAvailable =
(db.SaveTrackings.Where(s => s.BundleID == t.bundleID
&& s.UserID == t.userID)
.Count() > 0) ? true : false;
}
This is what I think understand: .Where() is returning all the entries with the matching IDs and then the .Count() is just seeing how many are there. I only feel like I half understand what we need s for.
I know what to expect from this code since it's been in use I just don't understand how it works and some of the documentation from MSDN is using some terminology that is confusing me.
All lambda expressions use the lambda
operator =>, which is read as "goes
to". The left side of the lambda
operator specifies the input
parameters (if any) and the right side
holds the expression or statement
block. The lambda expression x => x *
x is read "x goes to x times x."
So how am I suppose to understand what my code means based on this, .Where(s "goes to" s.BundleID == t.BundleID...) so what's happening here? What does "goes to" mean? Is it comparing every ID in s to everyone one available in t? How do I understand why it's called "goes to" and what exactly is happening?
And then it gets more confusing...
The => operator has the same
precedence as assignment (=) and is
right-associative.
Lambdas are used in method-based LINQ
queries as arguments to standard query
operator methods such as Where.
When you use method-based syntax to
call the Where method in the
Enumerable class (as you do in LINQ to
Objects and LINQ to XML) the parameter
is a delegate type System.Func. A lambda expression is the
most convenient way to create that
delegate.
What is a delegate type System.Func<T, TResult> and how is it created with this "goes to" operator?
I can't just use code because I know that it's working, I need to understand how/why.
Maybe it would help to see this function implemented by hand:
using System;
using System.Collections.Generic;
namespace CSharpSandbox
{
class Program
{
static IEnumerable<T> Where<T>(IEnumerable<T> input, Func<T, bool> predicate)
{
foreach (T item in input)
{
if (predicate(item))
yield return item;
}
}
static void Main(string[] args)
{
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IEnumerable<int> evens = Where(numbers, n => n % 2 == 0);
foreach (int even in evens)
{
Console.WriteLine(even);
}
}
}
}
The construct name => someEvaluation creates an anonymous function consisting of the following parts:
name is simply the name of a parameter, its type is inferred from its usage. You need a name so you can refer to the argument passed in the function.
=> is the start of your anonymous functions body, the scope of the body is a single expression.
someEvaluation is the body of your anonymous function composed of a single expression.
In our case, Func<T, bool> defines a function which takes a single parameter of type T and returns an output of type bool. (If we had used Func<T, U, bool>, we'd take two inputs of type T and U and return a bool. The last type parameter in the Func definition is the return value.)
You can invoke an instance of Func exactly as you invoke any other function. If the func takes params, you pass them in as expected, your parameters are bound to the variable names you defined. When you invoke the function, control flow will jump inside your function and evaluate its results.
In principle, you don't need to create a Func anonymously. You can pass in any function which has a compatible type signature, such as:
static bool IsEven(int n)
{
return n % 2 == 0;
}
static void Main(string[] args)
{
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
IEnumerable<int> evens = Where(numbers, IsEven);
foreach (int even in evens)
{
Console.WriteLine(even);
}
}
This program produces the same output. In fact, behind the scenes, the syntax name => expression is syntax sugar; when it gets compiled, C# will produce a produce a private function with a hidden name and convert it to the format above.
If it helps, think of s as a variable of type SaveTracking. It's iterating over each s in your collection/table, and testing the value of its BundleID.
The t is same idea - it's like it's iterating through all the return collection from the getAll.
It's like the SQL pseudocode:
SELECT * FROM SaveTracking INNER JOIN GetAll
ON BundleID AND UserID
For a deeper technical description of what's going on with lambda expressions, check out Jon Skeet's book C# In Depth. Chapter 9 , p 230. I found this book very helpful.
Lambda expressions are just a way to shorten the code but it does exactly the same things as declaring a method that corresponds to the delegate type System.Func<T, TResult>
I believe that C# converts your lamba to a method in the background when you compile and it looks like this :
bool LambdaExpression(YourType s)
{
return s.BundleID == t.bundleID && s.UserID == t.userID;
}

Categories

Resources