So, I ran across an answer by Servy ( https://stackoverflow.com/a/15098242/496680 ) and some of his code does this:
public static int BinarySearch<TSource, TKey>(...)
for an extension method, but he calls it like this:
arr.BinarySearch(...)
I asked around and somebody metioned that its an implied generic type parameter.
I googled them but found no information on them.
I understand how generics work but I'm failing to understand how/when to use these.
Why does servy use them in his extention method?
Is there a more official name for these that I can search for?
Well, you left out the most important part that makes it all work. The type parameters can be inferred by the actual object parameters passed in.
For instance:
static class Extensions {
internal static IEnumerable<U> Test<T, U>(
this IEnumerable<T> items,
Func<T, U> converter) {
foreach (T item in items) {
yield return converter(item);
}
}
}
This extension method works on any IEnumerable class and will convert each item in the enumeration to another type based on the converter you provided. This is standard generics.
Now, there are many ways to call this method:
IEnumerable<int> values = Enumerable.Range<int>(1, 10);
Func<int, string> converter = i => i.ToString("0.00");
// Variation 1, explicit calling
IEnumerable<string> results1 = Extensions.Test<int, string>(values, converter);
// Variation 2, explicit calling with type inference
IEnumerable<string> results2 = Extensions.Test(values, converter);
// Variation 3, extension method calling, still providing explicit types
IEnumerable<string> results3 = values.Test<int, string>(converter);
// Variation 4, extension method with type inference
IEnumerable<string> results4 = values.Test(converter);
All four variations call the same method and return the same result. Type inference works by looking at the parameters passed and automatically inferring their types based on what's being provided. In our examples above, it's able to determine that type T is of type int because we passed in an IEnumerable<int> into the parameter for IEnumerable<T>. It is also able to infer that type U is of type string because we passed in a Func matching the initial type of T with int and returning a string. So the Func<T, U> is filled in with our converter function of Func<int, string>.
From the inference above, it's a standard generic method at that point. Type inference and extension methods are nothing more than convenience/syntactic sugar. In fact, if you decompile the output you can see that extension methods are replaced with static calls and are usually defined with the type parameters explicitly filled out. (This varies based on your decompiler and the set options).
He uses a generic method in this case because it allows his method to work with any type contained within a Collection<T>. The generic method makes this very flexible, and usable for any type. He uses the type inferrence when calling the method because it simplifies the code at the call site.
The automatic handling is called Type Inferrence, and is covered, in detail, in the C# Language Specification, section 7.5.2: Type Inferrence. If you want to understand it in detail, I would recommend downloading the C# language specification.
The term I usually hear is 'type inference'.
Related
I am writing a simple Memoize helper that allows caching method results instead of computing them every time. However, when I try to pass a method into Memoize, the compiler can't determine the type arguments. Aren't they obvious from my method signature? Is there a way around this?
Sample code:
using System;
using System.Collections.Concurrent;
public static class Program
{
public static Func<T, V> Memoize<T, V>(Func<T, V> f)
{
var cache = new ConcurrentDictionary<T, V>();
return a => cache.GetOrAdd(a, f);
}
// This is the method I wish to memoize
public static int DoIt(string a) => a.Length;
static void Main()
{
// This line fails to compile (see later for error message)
var cached1 = Memoize(DoIt);
// This works, but is ugly (and doesn't scale to lots of type parameters)
var cached2 = Memoize<string, int>(DoIt);
}
}
Error message:
error CS0411: The type arguments for method 'Program.Memoize<T, V>(Func<T, V>)'
cannot be inferred from the usage. Try specifying the type arguments explicitly.
Isn't DoIt() signature compatible with Func<string, int>?
Yes it is. It's fine to convert it to that specific type, like this for example:
Func<string, int> func = DoIt;
var cachedDoit = Memoize(func);
The problem you're running into is that type inference basically doesn't work particularly well with method group conversions. When you pass DoIt as an argument, that's a method group. In your case it only refers to a single method, but it could refer to multiple methods, with different signatures... and that complicates things.
I often see this come up with LINQ, where I'd like to call foo.Select(SomeMethodGroup), but type inference fails. There's some support for method groups within type inference, but it's not everything we might want it to be.
This isn't a matter of the C# team being lazy... type inference is hugely complicated, and any change is really fraught with danger in terms of backward compatibility. It's in section 7.5.2 of the C# 5 specification if you want to have a look - but frankly that's part of the spec where I get lost really quickly.
Just wondering how C# determines the order of execution on an object in Method Overload
For instance I have a Method
bool SomeMethod(IQueryable source)
{
//.... Do Work
}
bool SomeMethod(IEnumerable source)
{
//.... Do Work
}
var Obj = Db.Table.Where(ID > 5);
SomeMethod(Obj);
When I run this the code goes to the IQueryable Overload, Now is that because I declared IQueryable First, is it because IQueryable is of Type IEnumerable or is there some other underlying reason why?
-Thanks
There is a betterness algorithm (section 7.4.3 of the C# spects) for deciding which method overload to use in the event that there are multiple applicable overloads. In this case an IQueryable is implicitly convertible to an IEnumerable, but an IEnumerable is not implicitly convertible to an IQueryable, making IQueryable the "better" overload.
See Also
7.4.2.3 Better conversion
.NET compiler is always looking for a most specific overload. Suppose you have a simple function that accepts a single parameter, with overloads for object and string parameters. If you are passing a string, string is an object, but string overload is more specific, so it will be called. With complex function signatures and many overloads sometimes you get compiler error "not most specific". See also:
Overload resolution failed because no accessible 'method' is most specific for these arguments:error
So, I ran across an answer by Servy ( https://stackoverflow.com/a/15098242/496680 ) and some of his code does this:
public static int BinarySearch<TSource, TKey>(...)
for an extension method, but he calls it like this:
arr.BinarySearch(...)
I asked around and somebody metioned that its an implied generic type parameter.
I googled them but found no information on them.
I understand how generics work but I'm failing to understand how/when to use these.
Why does servy use them in his extention method?
Is there a more official name for these that I can search for?
Well, you left out the most important part that makes it all work. The type parameters can be inferred by the actual object parameters passed in.
For instance:
static class Extensions {
internal static IEnumerable<U> Test<T, U>(
this IEnumerable<T> items,
Func<T, U> converter) {
foreach (T item in items) {
yield return converter(item);
}
}
}
This extension method works on any IEnumerable class and will convert each item in the enumeration to another type based on the converter you provided. This is standard generics.
Now, there are many ways to call this method:
IEnumerable<int> values = Enumerable.Range<int>(1, 10);
Func<int, string> converter = i => i.ToString("0.00");
// Variation 1, explicit calling
IEnumerable<string> results1 = Extensions.Test<int, string>(values, converter);
// Variation 2, explicit calling with type inference
IEnumerable<string> results2 = Extensions.Test(values, converter);
// Variation 3, extension method calling, still providing explicit types
IEnumerable<string> results3 = values.Test<int, string>(converter);
// Variation 4, extension method with type inference
IEnumerable<string> results4 = values.Test(converter);
All four variations call the same method and return the same result. Type inference works by looking at the parameters passed and automatically inferring their types based on what's being provided. In our examples above, it's able to determine that type T is of type int because we passed in an IEnumerable<int> into the parameter for IEnumerable<T>. It is also able to infer that type U is of type string because we passed in a Func matching the initial type of T with int and returning a string. So the Func<T, U> is filled in with our converter function of Func<int, string>.
From the inference above, it's a standard generic method at that point. Type inference and extension methods are nothing more than convenience/syntactic sugar. In fact, if you decompile the output you can see that extension methods are replaced with static calls and are usually defined with the type parameters explicitly filled out. (This varies based on your decompiler and the set options).
He uses a generic method in this case because it allows his method to work with any type contained within a Collection<T>. The generic method makes this very flexible, and usable for any type. He uses the type inferrence when calling the method because it simplifies the code at the call site.
The automatic handling is called Type Inferrence, and is covered, in detail, in the C# Language Specification, section 7.5.2: Type Inferrence. If you want to understand it in detail, I would recommend downloading the C# language specification.
The term I usually hear is 'type inference'.
I am trying to understand specifically why it is neccessary to have this Where<TSource>
What does the type straight after Where tell you?
I understand the 'this' concept which means its an extension method but cannoth understand the type after Where
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, bool> predicate
)
Func<TSource, bool> is a pointer to a function which takes TSource as parameter and returns boolean. For example if you had the following function:
public bool Foo(SomeType abc)
{
return abc.SomeProperty == "123";
}
you could pass it as argument to the Where method if you had a list of SomeType:
SomeType[] values = ...
var result = values.Where(Foo);
You could also use an anonymous function which avoids you the need to declare another function explicitly:
SomeType[] values = ...
var result = values.Where(x => x.SomeProperty == "123");
UPDATE:
I seem to have misunderstood the question. The type after the name of the function Where<TSource> indicates a generic function definition. It indicates that this function has a generic argument which can be of any type. So for example when you write:
SomeType[] values = ...
var result = values.Where(x => x.SomeProperty == "123");
TSource equals SomeType and the compiler is capable of automatically inferring it from the delegate. You could specify it explicitly but it's too much of a writing:
SomeType[] values = ...
IEnumerable<SomeType> result = values.Where<SomeType>(x => x.SomeProperty == "123");
The type in <...> after Where is a declaration of generic type parameter. The Where method is generic which means that some of the types involved in its type declaration can be provided when the method is used. In C#, this is called generics.
The <...> is a place where you declare types that the caller needs to specify when using your method. It is, in some way, similar to declarations of parameters
When using parameters, you say that the caller needs to give you some values and you give them names (e.g. source and predicate).
When writing generic method, you say that the caller needs to give you some type and you give the type a name (e.g. TSource) that you can use in the method declaration and body.
A simple answer to your question would be for type safety and IntelliSense while programming. (All the benifits that Generics provide).
LINQ to Objects works on Extension Methods defined in a type named Enumerable. Mostly, they deal with type IEnumerable<T>.
So, for example, when you want it to operate on a List<String>, the Where<TSource> becomes Where<String>. And C# 3.0 type inferance comes into picture so that you dont have to explicitly specify the String part. Since, the compiler knows you are working with IEnumerable<T>.
To sumarrize, when you use Where method on a List, the method expects an IEnumerable<String> and a Predicate that takes String to filter on input sequence as an input and provides with an IEnumerable<String> as an output.
So odd situation that I ran into today with OrderBy:
Func<SomeClass, int> orderByNumber =
currentClass =>
currentClass.SomeNumber;
Then:
someCollection.OrderBy(orderByNumber);
This is fine, but I was going to create a method instead because it might be usable somewhere else other than an orderBy.
private int ReturnNumber(SomeClass currentClass)
{
return currentClass.SomeNumber;
}
Now when I try to plug that into the OrderBy:
someCollection.OrderBy(ReturnNumber);
It can't infer the type like it can if I use a Func. Seems like to me they should be the same since the method itself is "strongly typed" like the Func.
Side Note: I realize I can do this:
Func<SomeClass, int> orderByNumber = ReturnNumber;
This could also be related to "return-type type inference" not working on Method Groups.
Essentially, in cases (like Where's predicate) where the generic parameters are only in input positions, method group conversion works fine. But in cases where the generic parameter is a return type (like Select or OrderBy projections), the compiler won't infer the appropriate delegate conversion.
ReturnNumber is not a method - instead, it represents a method group containing all methods with the name ReturnNumber but with potentially different arity-and-type signatures. There are some technical issues with figuring out which method in that method group you actually want in a very generic and works-every-time way. Obviously, the compiler could figure it out some, even most, of the time, but a decision was made that putting an algorithm into the compiler which would work only half the time was a bad idea.
The following works, however:
someCollection.OrderBy(new Func<SomeClass, int>(ReturnNumber))