Ambiguous C# method call with delegates [duplicate] - c#

This question already has answers here:
Compiler Ambiguous invocation error - anonymous method and method group with Func<> or Action
(4 answers)
Closed 7 years ago.
In my application, I have code similar to following:
class Program
{
static void Main(string[] args)
{
Method(uri => Task.FromResult(uri));
}
static void Method(Func<Uri, Uri> transformer)
{
throw new NotImplementedException();
}
static void Method(Func<Uri, Task<Uri>> transformer)
{
throw new NotImplementedException();
}
}
As expected, running this code calls the second overload of 'Method', the one expecting a function delegate that returns a task. However, if i change the code to avoid using the anonymous method in Main:
class Program
{
static void Main(string[] args)
{
Method(Method2);
}
static Task<Uri> Method2(Uri uri)
{
return Task.FromResult(uri);
}
static void Method(Func<Uri, Uri> transformer)
{
throw new NotImplementedException();
}
static void Method(Func<Uri, Task<Uri>> transformer)
{
throw new NotImplementedException();
}
}
The C# compiler now complains that my call to 'Method' is ambiguous. What am i missing?

The long answer is at https://stackoverflow.com/a/2058854/1223597 (as richzilla pointed out).
The short answer is that the C# compiler team chose to make method group conversions (like Method(Method2)) ignore the return type (here of Method2). This gives them flexibility in how Expression trees are parsed. Unfortunately that means the compiler cannot implicitly choose between your 2 Method signatures.
When doing a lambda conversion, (Method(uri => Task.FromResult(uri))), the compiler team doesn't need to worry about expression tree parsing, so they do consider return types.

Related

Is it possible to convert object to generic T?

The following code works fine:
public static void Main()
{
Foo<int>(5);
}
private static void Foo<T>(T x)
{
Bar((int)(object)x);
}
private static void Bar(int x)
{
}
However, my Bar method comes from a third-part library (Json.NET) that implements multiple overloads. Example:
private static void Bar(string x)
{
}
If I call Foo<int>(5), the Bar((int)(object)x) conversion works fine, but calling Foo<string>("") breaks at runtime (for obvious reasons, you can't convert string to int).
So, I would like to change the Bar((int)(object)x) conversion to a generic Bar((T)(object)x) conversion, but this gives the following compilation error:
cannot convert 'T' to 'int'
So, is it possible to convert object to T or the only solution is to using a switch-case convertion?
The error actually means that the compiler doesn't know which overload of Bar to invoke, since T could be any type at compile time.
You would need check if T is int or string at runtime and explicitly cast to the needed type.
if (typeof(T) == typeof(int))
Bar((int)(object)x);
else if (typeof(T) == typeof(string))
Bar((string)(object)x);
else
throw new Exception();

C# How to call function from generic code

I'm new to C# and I'm trying to make a generic type dispatcher (C++ like), but it looks like I can't call a function with a generic parameter:
Sample code:
class Program
{
static void Main(string[] args)
{
DoSomething(1);
}
static void DoSomething<T>(T value)
{
//error CS1503: Argument 1: cannot convert from 'T' to 'int'
DoSomethingElse(value);
}
static void DoSomethingElse(int a)
{
Console.Write("int\n");
}
static void DoSomethingElse(float a)
{
Console.Write("float\n");
}
}
Can you please explain why I can't call DoSomethingElse from DoSomething?
How may I forward value to another function that accepts that specific type?
This is probably not the cleanest way to deal with it, but you can cast to dynamic.
The problem is, if you don't have a method implemented for whatever type T is, it will crash at runtime. You may be able to narrow that problem a bit by adding a constraint to your generic parameter.
static void DoSomething<T>(T value) where T : struct
{
DoSomethingElse((dynamic)value);
}
Without any constraints, you are only permitted to do activities that you could do if value is of type object. You can use the is and as keywords to work around this.
If you add a where constraint such as where T : IComparable, you are permitted to use methods and properties that meet the constraint.
i.e. with the IComparable constraint, you could call value.CompareTo(x)
static void DoSomething<T>(T value)
{
if (value is int)
{
DoSomethingElse((value as int?).Value);
}
else if (value is float)
{
DoSomethingElse((value as float?).Value);
}
else
{
throw new Exception("No handler for type " + typeof(T).Name);
}
}

C# more specific version on generic function

I have the following function
public static T Translate<T>(T entity)
{
....
}
Now if T is en IEnumerable<> I want to have a different behaviour so I made a second function
public static IEnumerable<T> Translate<T>(IEnumerable<T> entities)
{
....
}
When I invoke it like this
IEnumerable<string> test = new List<string>().AsEnumerable();
Translate(test);
However when I invoke it like this
Func<IEnumerable<string>> func = () => new List<string>().AsEnumerable();
Translate(func.Invoke())
It goes to the first one.
Why does this happen and what is the best construction to solve this?
UPDATE
I build a new example with the problem
static void Main(string[] args)
{
Func<IEnumerable<string>> stringFunction = () => new List<string>().AsEnumerable();
InvokeFunction(ExtendFunction(stringFunction));
}
private static T Convert<T>(T text) where T : class
{
return null;
}
private static IEnumerable<T> Convert<T>(IEnumerable<T> text)
{
return null;
}
private static Func<T> ExtendFunction<T>(Func<T> func) where T : class
{
return () => Convert(func.Invoke());
}
private static T InvokeFunction<T>(Func<T> func)
{
return func.Invoke();
}
The first function gets invoken now when I expect the second to be invoked.
You need to either add a second overload of ExtendFunction:
private static Func<IEnumerable<T>> ExtendFunction<T> (Func<IEnumerable<T>> func) where T : class
{
return () => Convert(func.Invoke());
}
Or make the first overload invoke Convert method dynamically:
private static Func<T> ExtendFunction<T> (Func<T> func) where T : class
{
return () => Convert((dynamic)func.Invoke());
}
The reason is that your ExtendFunction method chooses Convert method at compile time. You can avoid that be either adding a second overload of ExtendFunction which chooses the Convert method you need, or by moving the choice of Convert method to run time.
In C#, the closest to specialization is to use a more-specific overload; however this works only when the type is know at compile time.
In your case the type is decided at run time because of IEnumerable<T>, but the compiler cannot guarantee that it will be IEnumerable<T>.
If you add this line in your main method you'll get the second function called.
Convert(text: new List<string>().AsEnumerable());
this is because the type is know at compile time
so try your Main in this way and look the differences
static void Main(string[] args)
{
Func<IEnumerable<string>> stringFunction = () => new List<string>().AsEnumerable();
InvokeFunction(ExtendFunction(stringFunction));//first function invoked
Convert(text: new List<string>().AsEnumerable());//second function invoked
}
I had the same problem a few weeks ago. You can solve this by specifying the type explicitely on calling the method but that's not really worth it, because it means everybody using your methods have to know about this fact.
We solved our problem by actually giving the method another name. In your case, that would be a second method named:
public static IEnumerable<T> TranslateAll<T>(IEnumerable<T> entities)

C# Polymorphysm: overloading function, accepting delegates Action<T> and Func<T,R>?

Here's a simple code, where I try to implement some sort of polymorphysm.
You can see overloaded Invoker function, accepting Func<T,R> and Action<T> as an argument.
Compiler says it couldn't be compiled because of ambiguity if Invoker methods:
class Program
{
static void Invoker(Action<XDocument> parser)
{
}
static void Invoker(Func<XDocument,string> parser)
{
}
static void Main(string[] args)
{
Invoker(Action);
Invoker(Function);
}
static void Action(XDocument x)
{
}
static string Function(XDocument x)
{
return "";
}
}
I get 3(!) errors, and none of it i can explain. Here they are:
Error 1 The call is ambiguous between the following methods or properties: 'ConsoleApplication3.Program.Invoker(System.Action)' and 'ConsoleApplication3.Program.Invoker(System.Func)' c:\users\i.smagin\documents\visual studio 2010\Projects\ConsoleApplication3\ConsoleApplication3\Program.cs 21 4 ConsoleApplication3
Error 2 The call is ambiguous between the following methods or properties: 'ConsoleApplication3.Program.Invoker(System.Action)' and 'ConsoleApplication3.Program.Invoker(System.Func)' c:\users\i.smagin\documents\visual studio 2010\Projects\ConsoleApplication3\ConsoleApplication3\Program.cs 22 4 ConsoleApplication3
Error 3 'string ConsoleApplication3.Program.Function(System.Xml.Linq.XDocument)' has the wrong return type c:\users\i.smagin\documents\visual studio 2010\Projects\ConsoleApplication3\ConsoleApplication3\Program.cs 22 12 ConsoleApplication3
Any ideas?
Both
static void Action(XDocument x)
and
static string Function(XDocument x)
have same method signature.
Return value is not part of method signature. So, just having a different return type won't work. They must have different number of parameters or parameter types must be different.
Since, compiler cannot figure out which one (method that takes Action or method that takes Func) to use, you have to explicitly specify it:
Invoker(new Action<XDocument>(Action));
Invoker(new Func<XDocument, String>(Function));
to resolve ambiguity.
You can invoke your methods like that:
public static void Main(string[] args)
{
Invoker(new Action<XDocument>(Action));
Invoker(new Func<XDocument, string> (Function));
}
Simply, you have to tell compiler what method you want to invoke.
Slightly more elegant solution using linq:
public static void Main(string[] args)
{
Invoker((xdocument)=>doSomething); // calls action invoker
Invoker((xdocument)=>{return doSomething;}); // calls function invoker
}
At the end of it... comes down to signatures.

Print property name (not what you would think) [duplicate]

This question already has answers here:
Get property name and type using lambda expression
(4 answers)
Closed 9 years ago.
This is a cursory question I can't quite answer.
The main program
class Program{
static void Main(string[] args){
Console.WriteLine("Begin");
var myClass = new MyClass();
Util.Print(myClass.Id);
Util.Print(myClass.Server);
Util.Print(myClass.Ping);
Console.WriteLine("End");
}
}
How do I implement the Util.Print method to get this output to the console:
Begin
Id
Server
Ping
End
Assuming you don't want to use strings, the most common answer is via an Expression - essentially emulating the missing infoof; you would have to use something like:
Console.WriteLine("Begin");
var myClass = new MyClass();
Util.Print(() => myClass.Id);
Util.Print(() => myClass.Server);
Util.Print(() => myClass.Ping);
Console.WriteLine("End");
Assuming they are all properties/fields (edit added method-call support):
public static class Util
{
public static void Print<T>(Expression<Func<T>> expr)
{
WriteExpression(expr);
}
public static void Print(Expression<Action> expr) // for "void" methods
{
WriteExpression(expr);
}
private static void WriteExpression(Expression expr)
{
LambdaExpression lambda = (LambdaExpression)expr;
switch (lambda.Body.NodeType)
{
case ExpressionType.MemberAccess:
Console.WriteLine(((MemberExpression)lambda.Body)
.Member.Name);
break;
case ExpressionType.Call:
Console.WriteLine(((MethodCallExpression)lambda.Body)
.Method.Name);
break;
default:
throw new NotSupportedException();
}
}
}
In addition to Marc's answer: here is an article which explains several ways to do what you want to do (one such method uses expressions).
public string Id {
get {
return "Id;"
}
}
Hehe erm, though I assume that's not what you mean :-( The answer will likely be something to do with reflection.
Take a look at http://msdn.microsoft.com/en-us/library/ms173183(VS.80).aspx

Categories