C#6 Overload Resolution Func<T1> & Func<T2> - c#

I know from this question\answer that the improvements in the overload resolution is that it includes the return type of a lambda in the resolution of the overload.
The example given on the site linked in the answer gives this:
class Program
{
private static void TakesItem(Action item)
{
}
private static int TakesItem(Func<int> item)
{
return item();
}
public static int somefunction()
{
return 50;
}
static void Main(string[] args)
{
int resultitem = TakesItem(somefunction);
Console.WriteLine(resultitem);
Console.ReadKey();
}
}
This code will compile in version 6 and not in version 5.
I've tried changing it functions returning different types:
private void Foo(Func<int> func)
{
}
private void Foo(Func<string> func)
{
}
private int Bar()
{
return 1;
}
[Test]
public void Example()
{
Foo(Bar);
}
This doesn't compile in C# 6 though, despite the Func returning different values.

It seems to me that the relevant part of the specification changes is here:
7.5.3.5 Better conversion target
Given two different types T1 and T2, T1 is a better conversion target than T2 if
…
•T1 is either a delegate type D1 or an expression tree type Expression<D1>, T2 is either a delegate type D2 or an expression tree type Expression<D2>, D1 has a return type S1 and one of the following holds:
◦D2 is void returning
◦D2 has a return type S2, and S1 is a better conversion target than S2
…
Note that void-returning delegate types are special-cased. So in the new rules, Func<int> is a "better conversion target" than Action, because Action is void-returning.
In your second example, where there is still ambiguity, that is because the conversion doesn't meet any of the requirements stated. Both delegate types are not void-returning, and neither delegate type's return type is "better" than the other. That is, int is not "better than" string.
Note that int is "better than" object. So if you change the Func<string> to Func<object>, the compiler is able to choose and you no longer get the error.

Related

Compilation error when i used lambda creator with base type for `Where` condition in linq

I have some part of code. It's not real code but very similar with my problem in production.
Call of ASupplier in point 2 not compiled cause result of var filtered is List<IA>. It's look's like valid cause Where declared as
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
But i can't understand why point 3 is valid because FixedIACondition declaration similar with result of call IAConditionCreator
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqWhereConditionProblem
{
internal class Program
{
public static void Main(string[] args)
{
var collection = new List<A>();
ASupplier(collection); // 1) OK
var filtered = collection.Where(IAConditionCreator("a")).ToList();
ASupplier(filtered); // 2) NOT OK
var filtered2 = collection.Where(FixedIACondition).ToList();
ASupplier(filtered2); // 3) OK
}
private static void ASupplier(IReadOnlyCollection<A> aCollection)
{
foreach (var a in aCollection)
{
Console.WriteLine(a.GetText());
}
}
private static Func<IA, bool> IAConditionCreator(string value)
{
return a => a.GetText() == value;
}
private static bool FixedIACondition(IA ia) => ia.GetText() == "aa";
}
public interface IA
{
string GetText();
}
public class A : IA
{
public string GetText()
{
return "ABC";
}
}
}
The way the compiler does implicit type conversion is different for delegate objects and method groups and I guess its main goal is to reduce the number of type conversions (including implicit type conversions) as far as possible.
The method FixedIACondition is referenced as a method group that the compiler has to convert to a delegate object anyhow. The compile is able to infer that this method group can be converted into a Func<A, bool>, which is the type required by .Where.
For IAConditionCreator, the compiler already has a delegate object and now tries to fit that object into the call. However, it has to convert either the collection to IEnumerable<IA> or to convert the delegate to Func<A, bool>. The support for covariant delegates is not that good in .NET (try calling Delegate.Combine) and I guess the compiler team is aware of that and thus tries to avoid this and rather go for the first conversion.
Changing method ASupplier to receive IASupplier resolves this issue:
private static void ASupplier(IReadOnlyCollection<IA> aCollection)
{
foreach (var a in aCollection)
{
Console.WriteLine(a.GetText());
}
}
If you only care about the interface, this may be what you want. If ASupplier is solely to handle type A, you can either Cast or filter from the list those OfType A
ASupplier(filtered.OfType<A>().ToList()); // this will filter the list to return those of type A
ASupplier(filtered.Cast<A>().ToList()); // this will throw exception if any object can't be cast to A
Another option is casting the Func itself to return the type you want:
var condition = (Func<A, bool>)IAConditionCreator("a");
var filtered = collection.Where(condition).ToList();
ASupplier(filtered);
There are other ways to handle polymorphism, but then you'll have to be more specific about your scenario.

Lambda of "x => { throw .. }" inferred to match Func<T,Task> in overloaded method?

I don't understand why C# ends up executing an incorrect extension method in the following LINQPad code:
void Main()
{
// Actual: Sync Action
"Expected: Sync Action".Run(x => { x.Dump(); });
// Actual: Async Task
"Expected: Async Task".Run(async x => { await System.Threading.Tasks.Task.Run(() => x.Dump()); });
// Actual: Async Task!!
"Expected: Sync Action".Run(x => { throw new Exception("Meh"); });
}
static class Extensions
{
public static void Run<T>(this T instance, Action<T> action)
{
"Actual: Sync Action".Dump();
action(instance);
}
public static void Run<T>(this T instance, Func<T, System.Threading.Tasks.Task> func)
{
"Actual: Async Task".Dump();
func(instance).Wait();
}
}
Why does the compiler think that the lambda returns a Task here?
I expected to see "Actual: Sync Action" in the third call to Run() since nothing in the lambda indicates that this is a Func returning Task.
This is simply an overload resolution issue. Clearly, the lambda x => { throw new Exception("Meh"); } can be converted to either an Action<T> or to a Func<T, SomeNonVoidType> (as well as to many other delegate types irrelevant to this question). It's simply C#'s overload resolution rules that prefer the latter in this case.
Here's a more representative example:
void Main()
{
// Output: Func<T, int>
"Test".WhatsThis(x => { throw new Exception("Meh"); });
}
static class Extensions
{
public static void WhatsThis<T>(this T dummy, Action<T> action)
{
"Action<T>".Dump();
}
public static void WhatsThis<T>(this T dummy, Func<T, int> func)
{
"Func<T, int>".Dump();
}
}
As for why this is the case, I'm not 100% sure, but a casual look at the spec shows me the below likely explanation (emphasis mine):
7.5.3 Overload resolution
[...]
7.5.3.3 Better conversion from expression
Given an implicit conversion C1 that converts from an expression E to a type T1, and an implicit conversion C2 that converts from an expression E to a type T2, C1 is a better conversion than C2 if at least one of the following holds:
[...]
• E is an anonymous function, T1 is either a delegate type D1 or an expression tree type
Expression<D1>, T2 is either a delegate type D2 or an expression tree
type Expression<D2> and one of the following holds:
[...]
• D1 has a return type Y, and D2 is void returning

Having an ambiguity issue in C#

I have the follow program:
static void Main(string[] args)
{
CaptureFunction(MyFunction); // This line gets an error: "The call is ambiguous between the following methods or properties: CaptureFunction(System.Func<object,object>) and CaptureFunction(System.Func<int,int>)"
CaptureFunction(MyFunction2);
}
static void CaptureFunction(Func<object,object> myFunction)
{
myFunction.DynamicInvoke(3);
}
static void CaptureFunction(Func<int, int> myFunction)
{
myFunction.DynamicInvoke(3);
}
static object MyFunction(object a)
{
if (a is int)
return ((int) a)*3;
return 0;
}
static int MyFunction2(int a)
{
return a * 3;
}
I am trying to figure out why I am getting an ambiguity error at that line. They clearly have two different parameter signatures. I understand that an int can also be boxed into an object, however, I would except C# to call the CaptureFunction(Func<int, int>) method if I pass actual int values, otherwise it should call the other CaptureFunction() method. Can someone please explain this and please offer a possible work around?
This is due to covariance/contavariance introduced in .Net 4. See here for info. Because int is castable to object the compiler can't decide which function you are pointing to (as Func is castable to Func) Sorry, not .Net 4
The following compiles:
static void Main(string[] args)
{
CaptureFunction((Func<object,object>)MyFunction); // This line gets an error: "The call is ambiguous between the following methods or properties: CaptureFunction(System.Func<object,object>) and CaptureFunction(System.Func<int,int>)"
CaptureFunction(MyFunction2);
}
static void CaptureFunction(Func<object,object> myFunction)
{
myFunction.DynamicInvoke(3);
}
static void CaptureFunction(Func<int,int> myFunction)
{
myFunction.DynamicInvoke(3);
}
static object MyFunction(object a)
{
if(a is int)
return ((int)a)*3;
return 0;
}
static int MyFunction2(int a)
{
return a * 3;
}
Note the casting to Func<object,object>
Try to use dynamic if you are using C#.net 4.0
static void CaptureFunction(Func<dynamic, dynamic> myFunction)
{
myFunction.DynamicInvoke(3);
}
if you are not using 4.0 then just use object type.
static void CaptureFunction(Func<object, object> myFunction)
{
myFunction.DynamicInvoke(3);
}
remove the other overload of CaptureFunction which has a type of int.
You are passing a delegate for MyFunction... but which one? It could be either... either would work.
There are overloads of CaptureFunction that will accept either MyFunction signature. So it has no way to know which one you mean.
It seems like the function given satisfies both delegate signatures. You can work around this by declaring the func explicitly:
Func<int, int> intFunc = MyFunction2;
Func<object, object> objFunc = MyFunction;
CaptureFunction(intFunc);
CaptureFunction(objFunc);

Compiler can't figure out generic types when passing a method

I'm having trouble with C# and generic type inference.
I want to write a method that gets passed a method having any type, but the compiler is not able to infere the types of the method I'm passing in. The compiler always complains with with the message
Expected a method with '??? TestFunc(???, ???)' signature
Here's a testcase.
using System;
public class Example
{
private interface ITest
{
int TestFunc(string str, int i);
}
private class Test : ITest
{
public int TestFunc(string str, int i) { return 0; }
}
public static void Main()
{
ITest t = new Test();
DoWork(t.TestFunc);
}
public static void DoWork<T1, T2, TResult>(Func<T1, T2, TResult> func)
{
}
}
Can anyone explain me what's the problem?
The rules for type inference are hideously complicated, unfortunately. At least, I find them complicated, and I believe Eric and Mads are having another go at simplifying them for the next version of the spec - quite possibly not changing what's implemented, but changing how that's expressed in the spec.
In this case, the fundamental problem is that the parameter types of method groups don't contribute to type inference, even though the return type does. In particular, from 7.5.2.6 of the C# 4 spec:
Otherwise, if E is a method group and T is a delegate type or expression tree type with parameter types T1…Tk and return type Tb, and overload resolution of E with the types T1…Tk yields a single method with return type U, then a lower-bound inference is made from U to Tb.
That deals with return types, but doesn't specify anything about parameter types. The only relevant bit of the spec I can find about parameter types for method groups is this:
If E is a method group or implicitly typed anonymous function and T is a delegate type or expression tree type then all the parameter types of T are input types of E with type T.
That doesn't help to fix any bounds, unfortunately.
So basically, this works:
using System;
public class Example
{
private interface ITest
{
int TestFunc();
int TestFunc2(string value);
}
public static void Main()
{
ITest t = null;
DoWork(t.TestFunc);
DoWork2(t.TestFunc2);
}
public static void DoWork<TResult>(Func<TResult> func)
{
}
public static void DoWork2<TResult>(Func<string, TResult> func)
{
}
}
... because the only type parameter that needs to be inferred in either case is the return type. It's when you try to infer type parameters based on the input parameters of the method that things go wrong :(
I assume the compiler does not try to infer the type in this case, since if you have overloads of TestFunc, the desired behavior is not well defined. Consider:
private class Test
{
public int TestFunc(string str, int i) { return 0; }
public int TestFunc(string str, long i) { return 0; }
}
public static void Main()
{
Test t = new Test();
DoWork(t.TestFunc);
}
public static void DoWork<T1, T2, TResult>(Func<T1, T2, TResult> func)
{
}

Automatic type Conversion in C#

I know that you could override an object's ToString() Method, so that everytime you call an object or pass it to a function that requires a String type it will be converted to a String.
I have written several extension methods for object type 'object'
public static DateTime ToDate(this object date)
{
return DateTime.Parse(date.ToString());
}
public static int ToInteger(this object num)
{
return Int32.Parse(num.ToString());
}
public static long ToLong(this object num)
{
return Int64.Parse(num.ToString());
}
so that I could just call them like this:
eventObject.Cost = row["cost"].ToString();
eventObject.EventId = row["event_id"].ToLong();
However, what I want to accomplish is to convert the row objects which is of type 'object' to its correct type based on the property types on my 'eventObject'. So, I could call it like this:
eventObject.Cost = row["cost"];
eventObject.EventId = row["event_id"];
The row is a DataRow if that matters.
C# supports implicit conversion for types and you can use it for your custom types like the following:
class CustomValue
{
public static implicit operator int(CustomValue v) { return 4; }
public static implicit operator float(CustomValue v) { return 4.6f; }
}
class Program
{
static void Main(string[] args)
{
int x = new CustomValue(); // implicit conversion
float xx = new CustomValue(); // implicit conversion
}
}
And supports extension methods, but doesn't support implicit conversion as an extension method like the following:
static class MyExtension
{
// Not supported
public static implicit operator bool(this CustomValue v)
{
return false;
}
}
I know that you could override an
object's ToString() Method, so that
everytime you call an object or pass
it to a function that requires a
String type it will be converted to a
String.
No, you are wrong. The following code won't compile:
class MyClass
{
public override string ToString()
{
return "MyClass";
}
}
static void MyMethod(string s) { }
static void Main(string[] args)
{
MyMethod(new MyClass()); //compile error
}
The compiler will not get the type of MyMethod parameter(which is string) first and try to convert the argument you passed(whose type is MyClass) to it. I guess you are probably mislead by something like Console.WriteLine. Base on the code above,
Console.WriteLine(new MyClass()) prints "MyClass" to the console, it seems that the compiler knows you should pass a string to Console.WriteLine and try to convert MyClass to string. But the essential is Console.WriteLine has several overloads, one of them is for object:
//from Console.cs
public static void WriteLine(object value)
{
//in this method there is something like
//Console.WriteLine(value.ToString());
}
I believe what you're looking for is implicit conversion, which is described here: http://msdn.microsoft.com/en-us/library/z5z9kes2.aspx.
However, adding these to object would be a very bad idea, for reasons outlined on the page I've linked to.
Forgive me if I'm stating the obvious but I got this impression after reading your question.
You know the basetype of every type in .NET is object right?
So the column in the datarow which you describe of type object could also just as well be of the same type as the member you're trying to assign to and then a simple cast is needed.
for instance
eventObject.EventId = (int)row["event_id"];
To sum up - just define these methods and you can use objects of class Test in methods requiring String as a parameter.
class Test
{
private String txt;
public static implicit operator string(Test t)
{
return t.ToString();
}
public override string ToString()
{
return txt;
}
}

Categories

Resources