Disambiguating between overloaded methods passed as delegates in an overloaded call - c#

Suppose I had this in C#:
class OverloadTest
{
void Main()
{
CallWithDelegate(SomeOverloadedMethod);
}
delegate void SomeDelegateWithoutParameters();
delegate void SomeDelegateWithParameter(int n);
void CallWithDelegate(SomeDelegateWithoutParameters del) { }
void CallWithDelegate(SomeDelegateWithParameter del) { }
void SomeOverloadedMethod() { }
void SomeOverloadedMethod(int n) { }
}
Of course, this does not compile, because the line CallWithDelegate(SomeOverloadedMethod); is ambiguous.
Now, suppose there was only one CallWithDelegate(SomeDelegateWithoutParameter del) function (no overloads). In this case, there would be no ambiguity, because, from what seems to be happening, the compiler can look at the parameter type and discard SomeOverloadedMethod(int n) from the candidate list (since it can only take a SomeDelegateWithoutParameters), and so it compiles.
I don't intend to write code like this; this is just out of curiosity, from a compiler writer point-of-view. I couldn't find an answer about this, since it is quite confusing to put into words.
I'd like to know if there is any way in C# to disambiguate that call in Main() in the example given, so that it would compile. How can you specify it so that it resolves into CallWithDelegate(SomeDelegateWithoutParameters del) being passed SomeOverloadedMethod(), or CallWithDelegate(SomeDelegateWithParameter del) being passed SomeOverloadedMethod(int n)?

There are several ways to disambiguate overload resolution of method groups.
Method 1: cast the method group
CallWithDelegate((SomeDelegateWithoutParameters)SomeOverloadedMethod);
CallWithDelegate((SomeDelegateWithParameter)SomeOverloadedMethod);
This disambiguates the overload. That's pretty uncommon syntax in the wild, but it works (C# 5 spec §6.6 Method group conversions):
As with all other implicit and explicit conversions, the cast operator can be used to explicitly perform a method group conversion.
[...]
Method groups may influence overload resolution, and participate in type inference.
Method 2: instantiate the delegate explicitly
CallWithDelegate(new SomeDelegateWithoutParameters(SomeOverloadedMethod));
CallWithDelegate(new SomeDelegateWithParameter(SomeOverloadedMethod));
This is the same as the previous method without the syntactic sugar. See the spec at §7.6.10.5 Delegate creation expressions for more details.
The binding-time processing of a delegate-creation-expression of the form new D(E), where D is a delegate-type and E is an expression, consists of the following steps:
If E is a method group, the delegate creation expression is processed in the same way as a method group conversion (§6.6) from E to D.
[...]
There's even an example closely related to your question:
As described above, when a delegate is created from a method group, the formal parameter list and return type of the delegate determine which of the overloaded methods to select. In the example
delegate double DoubleFunc(double x);
class A
{
DoubleFunc f = new DoubleFunc(Square);
static float Square(float x) {
return x * x;
}
static double Square(double x) {
return x * x;
}
}
the A.f field is initialized with a delegate that refers to the second Square method because that method exactly matches the formal parameter list and return type of DoubleFunc. Had the second Square method not been present, a compile-time error would have occurred.
Method 3: use a lambda
CallWithDelegate(() => SomeOverloadedMethod());
CallWithDelegate(i => SomeOverloadedMethod(i));
CallWithDelegate((int i) => SomeOverloadedMethod(i)); // Explicit types, if needed
This form is not ambiguous but it has an indirection (the lambda is called, and it then calls the target method). This may get optimized by the JIT though, and it most probably won't have a visible performance impact anyway.
Method 4: use anonymous delegates
CallWithDelegate(delegate() { SomeOverloadedMethod(); });
CallWithDelegate(delegate(int i) { SomeOverloadedMethod(i); });
This is equivalent to the lambda calls, but it uses the bulkier (and older) delegate syntax.
If you'd like to know the exact overload resolution rules, they're described in the spec in §7.5.3 Overload resolution.

While i am no compiler expert, I can tell you that since you have supplied 2 overloaded methods that match both methods the compiler has no way of identifying your actual intention. It can't compile because at compile time there is currently no actual identifying information as now mentioned by Lucas you can cast to remove the ambiguity. For the compiler to solve this it would need run-time information of which method you actually wanted to use based on arguments that you may try and pass in.

Related

make method in C# that takes function without type parameters

My eventual aim is to get a function that can take any other function - eg something like
void RegisterHandler( Delegate function);
however - I want to be able to call it without doing any casting, or without type parameters - obviously Delegate doesn't work. If I declare:
void RegisterHandler<T>( Func<T> function );
then it works fine - this works:
string Whatever() {return "hi";}
...
RegisterHandler( whatever );
however - as soon as I throw in parameters, it doesn't work
void RegisterHandler<TParam1,TReturn>( Func<TParam1, TReturn> function );
string Something( int x ) {return x.ToString();}
...
RegisterHandler( Something ); // doesn't compile - wants types specified
RegisterHandler<int,string>( Something ); // works, but is what I'm trying to avoid
I'd even be ok if "object" worked - this is just part of a fluent interface, and I just want to be able to call it. I read somewhere that the number of parameters has to be >= the number of template types, and I guess the return type is counted, so I can never fulfill that.
Bottom line - I can't find any c# signature that will accept any function that takes one parameter, and returns something. Is it possible?
Rather than attacking your problem directly, which needs some clarification, let me address your concerns here:
I read somewhere that the number of parameters has to be >= the number of template types
Let's crisp that up a bit.
First off, those are generic type parameters, not "template types". This isn't C++. Generics are similar to templates but they are not templates, and the sooner you stop thinking of them as templates, the better.
It is NOT true that the number of formal parameters needs to be greater than or equal to the number of generic type parameters declared by the generic method. For example:
static void M<K, V>(Dictionary<K, V> d) { }
...
Dictionary<int, string> d = whatever;
M(d); // No problem!
The number of formal parameters is one, the number of generic type parameters is two, but we have no problem doing type inference here.
The real rule is quite a bit more complicated. Rather, the real problem that you're running into is:
The conversion of a method group to a delegate requires that the parameter types of the delegate be known before the conversion happens.
Let's suppose we have:
int F(string x) { ... }
void M<A, R>(Func<A, R> f) { ... }
M(F);
What happens? We must determine what F means when converted to Func<A, R> but we know neither A nor R. How do we determine the meaning? We do overload resolution. That is, we would pretend that there was a call:
A a = whatever;
F(a)
and ask "which method named F would work?"
But we never even get to that step because we don't know what A is yet. Type inference fails to make progress. Now, if by contrast you had:
int F(string x) { ... }
void M<A, R>(A a, Func<A, R> f) { ... }
M("abc", F);
Now type inference first says "I deduce from the use of "abc" for a that A is string." After that inference is made, now overload resolution would succeed. If we did
string a = whatever;
F(a);
then overload resolution would determine that F means int F(string).
Once we have determined that F means int F(string), now we can ask the question "what can we deduce about the conversion from int F(string) to Func<string, R>, and from that we deduce R must be int and we're done.
I know what you're going to ask next. I only have one overload called F, so why don't we just pick it automatically?
There are many problems with making exceptions like that. First, special cases tend to multiply, and soon we have an even crazier inference algorithm that no one understands and it cannot be changed without causing bugs. Second, it makes your code brittle; it means that inference depends on the number of accessible methods named F in scope. Suppose you add a new private method also called F; does inference suddenly change?
No, the rule is straightforward and understandable once you know it. Method groups are resolved exactly the same as though there was a call to the method. But we cannot simulate a call until after the argument types are inferred.
Believe me, I know as well as anyone how tricky the type inference algorithm can be in C#; it has a lot of these sorts of surprising cases. If you have a more crisp question about the design, implementation or specification of this algorithm feel free to open up a new question and leave me a comment on this answer and I will try to have a look.
Are... you looking for Action?
Func<T> is a .net delegate that is meant to return a value.
Action is a .net delegate that does not return a value
Action<T> also accepts up to 16 params.

What is the value being passed into this lambda expression?

Forgive me if this is a stupid question but I am not sure where to look. I have this code that compiles fine:
static int Main(string[] args)
{
var parserResult = CommandLine.Parser.Default.ParseArguments<Options>(args);
parserResult.WithParsed<Options>(options => OnSuccessfulParse(options));
parserResult.WithNotParsed<Options>(errs =>
{
var helpText = HelpText.AutoBuild(parserResult, h =>
{
return HelpText.DefaultParsingErrorsHandler(parserResult, h);
}, e =>
{
return e;
});
Console.WriteLine(helpText);
ReturnErrorCode = ErrorCode.CommandLineArguments;
});
return (int)ReturnErrorCode;
}
My query has to do with this line of code:
parserResult.WithParsed<Options>(options => OnSuccessfulParse(options));
I understand that with a Lambda Expression the value on the left of the => is the value and value on the right is the expression.
What exactly is options? Why does it compile? It works absolutely fine. But what is it?
I don't know if this helps:
I might be barking up the wrong tree with my understanding of this. I admit I am struggling with the concept. Any explanation appreciated.
I see several questions but I can't explain it in my situation.
Update
OnSuccessfulParse declaration is:
private static void OnSuccessfulParse(Options options)
The WithParsed code is provided here
Lambda expression is the delegate of type Action<Options>. It is a callback from the parser into your code to inform you that the parse has been successful, and pass you Options object obtained as the result of the parse.
As far as options goes, it's just a name that you picked for the parameter to be passed into OnSuccessfulParse method. It is completely unnecessary here - this method group equivalent call will compile and run just the same:
parserResult.WithParsed<Options>(OnSuccessfulParse);
Here is the definition of WithParsed<T> method from github project:
public static ParserResult<T> WithParsed<T>(this ParserResult<T> result, Action<T> action)
{
var parsed = result as Parsed<T>;
if (parsed != null) {
action(parsed.Value);
}
return result;
}
This method is rather straightforward: it takes parse result, tries casting it to a successful parse, and if the cast is valid, calls a delegate that you supply. The WithNotParsed<T> method casts to unsuccessful NotParsed<T> result, and makes a call if the cast is valid.
That's a C# (.Net) way of representing function blocks.
Essentially an Action<Type> is an invocable type that roughly means pass an instance of Type in and execute the block.
E.g. we can write
public void Do(){
this.CallStuff(s => Console.WriteLine(s)); // or you can use a method group and do this.CallStuff(Console.WriteLine);
}
public void CallStuff(Action<string> action){
var #string = "fancy!";
action(#string);
}
In this case the s type is string.
In your example there is a type called Options defined somewhere and it is passed into an action.
Additionally, if you look at decompiled code, anonymous method blocks passed to actions are compiled as static anonymous types inside your class (because c# does not support dynamic code blocks, like, for example, obj-c does).
Another thing to look into are Func<out type> -> these are essentially the same as Action<> except the LAST type in the generic definition is the type they return.
UPD
#elgonzo raises a good point - Action<> and Func<> are actually just delegates; meaning that you can define a real method and pass it along as an Action or Func and then no anonymous static class will be compiled.
However in practice you will see that a lot of code defines those inline, and then the in-line code block needs to reside within a method somewhere, so the compiler puts it into the statis anonymous class.
What exactly is options?
options is i/p parameter to delegate represented by lambda expression
Why does it compile?
Simply because it adheres all syntactical and semantic rules of compiler ;) Like (x)=>x+1 is lambda expression to represent Func<int,int> (there can be another delegate to match same signature as well)
If your method expects Func<int,int> as parameter and argument passed is (x)=>x+1 then compiler infers this as x of type int. Compiled IL code would be equivalent to passing instance of delegate as an argument to method. Like :
call((x)=>x+1) will be compiled to call(new Func<int,int>(myMethod)) where call method definition is :
void Call(Func<int,int> someparam) {}
But what is it?
I think above response should have addressed this query.

Why is the compiler not able to infer the type of the method? [duplicate]

Consider
void Main()
{
var list = new[] {"1", "2", "3"};
list.Sum(GetValue); //error CS0121
list.Sum(s => GetValue(s)); //works !
}
double GetValue(string s)
{
double val;
double.TryParse(s, out val);
return val;
}
The description for the CS0121 error is
The call is ambiguous between the following methods or properties:
'System.Linq.Enumerable.Sum<string>(System.Collections.Generic.IEnumerable<string>,
System.Func<string,decimal>)' and
'System.Linq.Enumerable.Sum<string>(System.Collections.Generic.IEnumerable<string>,
System.Func<string,decimal?>)'
What I don't understand is, what information does s => GetValue(s) give the compiler that simply GetValue doesn't - isn't the latter syntactic sugar for the former ?
Mark's answer is correct but could use a bit more explanation.
The problem is indeed due to a subtle difference between how method groups are handled and how lambdas are handled.
Specifically, the subtle difference is that a method group is considered to be convertible to a delegate type solely on the basis of whether the arguments match, not also on the basis of whether the return type matches. Lambdas check both the arguments and the return type.
The reason for this odd rule is that method group conversions to delegates are essentially a solution of the overload resolution problem. Suppose D is the delegate type double D(string s) and M is a method group containing a method that takes a string and returns a string. When resolving the meaning of a conversion from M to D, we do overload resolution as if you had said M(string). Overload resolution would pick the M that takes a string and returns a string, and so M is convertible to that delegate type even though the conversion will result in an error later. Just as "regular" overload resolution would succeed if you said "string s = M(null);" -- overload resolution succeeds, even though that causes a conversion failure later.
This rule is subtle and a bit weird. The upshot of it here is that your method group is convertible to all the different delegate types that are the second arguments of every version of Sum that takes a delegate. Since no best conversion can be found, the overload resolution on method group Sum is ambiguous.
Method group conversions rules are plausible but a bit odd in C#. I am somewhat vexed that they are not consistent with the more "intuitively correct" lambda conversions.
s => GetValue(s) is a lambda expression and GetValue is a method group, which is a completely different thing. They can both be considered syntactic sugar for new Func<string,double>(...) but the only way they are related to each other is that the lambda expression includes a call to GetValue(). When it comes to converting to a delegate, method groups have different conversion rules than lambda expressions with respect to return types. See Why is Func<T> ambiguous with Func<IEnumerable<T>>? and Overloaded method-group argument confuses overload resolution?.

Write a method which accepts a lambda expression

I have a method with the following signature:
void MyMethod(Delegate d){};
void MyMethod(Expression exp){};
void MyMethod(object obj){};
However, this fails to compile:
MyMethod((int a) => a)
with the following error:
"Cannot convert lambda expression to type 'object' because it is not a delegate type"
Why doesn't this work?
Edit: I know that this works. The compiler compiles the lambda expression to a delgate in this case I think.
void MyMethod(Func<int, int> d){};
Kind regards,
Because the type System.Delegate isn't a "Delegate". It's just the base class. You have to use a delegate type with the correct signature. Define your Method as follows:
void MyMethod(Func<int, int> objFunc)
EDIT:
MyMethod(object) doesn't work because a lambda expression has no type at it's own, but the type is inferred from the type of the location it is assigned to. So object doesn't work either. You HAVE to use a delegate type with the correct signature.
void MyMethod(Action<int> lambdaHereLol)
{
lambdaHereLol(2);
}
in use:
var hurrDurr = 5;
MyMethod(x => Console.Write(x * hurrDurr));
C# is a statically typed language. The compiler needs to know the Type of everything it deals with. Lambdas are a bit hard to nail down, and sometimes the compiler can't figure it out. In my example above, if MyMethod took an object, the compiler couldn't figure out that x is an int (my example is simple, but there's nothing that says it can't be much more complex and harder to determine). So I have to be more explicit in defining the method that takes my lambda.
A lambda like (int a) => a will fit any delegate that takes an int and returns an int. Func<int,int> is just a single example, and you could easily declare one yourself with delegate int Foo(int x);. In fact this lambda expression will even fit a delegate that takes an int and returns a double, because the result of the lambda (a) is implicitly convertible to double.
In order for a lambda to be assignable to all the delegate types that it would fit, the lambda itself doesn't inherently have a type. Instead it takes on the type of the delegate you're using it as, as long as that's possible. ((int a) => a can't be assigned to Func<byte, byte> of course.)
While both Func<int, int> and the Foo delegate I defined can of course be converted to Delegate, a lambda can not be directly converted to Delegate because it is unclear what its actual signature would then be. After Delegate d = (int a) => a, would d be Foo, or Func<int, int>, or even Func<int, double>? All are valid possibilities, and the compiler has no idea what you intended. It could make a best guess, but C# is not the kind of language that does that kind of guesswork. This is also why you can't do something like var = (int a) => a.
I do think the error message that the compiler gives for Delegate d = (int a) => a; is very unclear:
Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type
Intuitively you would think Delegate is a delegate type, but that's not how things work. :)
Try this:
void MyMethod(Action<int> func) { }
You need to a strongly-typed delegate as a parameter to the method. The reason the other calls fail is because the C# compiler will not allow you to pass a lambda expression to a method expecting an Object because a lambda expression isn't necessarily always a delegate in all cases. This same rule applies for passing the lambda expression as a Delegate.
When you pass the lambda to a function like I have showed above, the compile can safely assume that you want the lambda expression to be converted to a specific delegate type and does so.
It's simply the nature of the compiler that you need to explicitly cast a delegate object to Delegate when passing it as a parameter of type Delegate. In fact, lambda expressions complicate things even further in that they are not implicitly convertable to delegates in this case.
What you require is a double cast, as such:
MyMethod((Delegate)(Func<int, int>)((int a) => a));
which of course corresponds to the method signature:
void MyMethod(Delegate d);
Depending on your situation, you may want to define a parameter of type Func<int> rather than Delegate (though I would hesitate adding an overload, just because it adds unnecessary complexity in honesty).
The reason this fails is the same reason an expression like "object del = (int a) => a" or even "var del = (int a) => a" fails. You might think that the compiler could figure out the type of your lambda expression since you explicitly give the type of the argument, but even knowing that the expression takes an int and returns an int, there are a number of delegate types it could be converted to. The Func delegate type is the one most used for generic functions such as this, but that is just a convention and nothing the compiler is aware of.
What you need to do is to cast the lambda expression to a concrete delegate type in order to have the compiler select the Delegate overload, either using the normal cast syntax (Func)((int a) => a), or using the delegate constructor syntax new Func((int a) => a).
Also, you normally do not want to use the untyped Delegate class unless you need to invoke something differently depending on the number of argument it accepts. It's almost always better to accept a Func or Action for things like callbacks.

Convert this delegate to an anonymous method or lambda

I am new to all the anonymous features and need some help. I have gotten the following to work:
public void FakeSaveWithMessage(Transaction t)
{
t.Message = "I drink goats blood";
}
public delegate void FakeSave(Transaction t);
public void SampleTestFunction()
{
Expect.Call(delegate { _dao.Save(t); }).Do(new FakeSave(FakeSaveWithMessage));
}
But this is totally ugly and I would like to have the inside of the Do to be an anonymous method or even a lambda if it is possible. I tried:
Expect.Call(delegate { _dao.Save(t); }).Do(delegate(Transaction t2) { t2.Message = "I drink goats blood"; });
and
Expect.Call(delegate { _dao.Save(t); }).Do(delegate { t.Message = "I drink goats blood"; });
but these give me
Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type** compile errors.
What am I doing wrong?
Because of what Mark Ingram posted, seems like the best answer, though nobody's explicitly said it, is to do this:
public delegate void FakeSave(Transaction t);
Expect.Call(delegate { _dao.Save(t); }).Do( new FakeSave(delegate(Transaction t2) { t.Message = expected_msg; }));
That's a well known error message. Check the link below for a more detailed discussion.
http://staceyw1.wordpress.com/2007/12/22/they-are-anonymous-methods-not-anonymous-delegates/
Basically you just need to put a cast in front of your anonymous delegate (your lambda expression).
In case the link ever goes down, here is a copy of the post:
They are Anonymous Methods, not
Anonymous Delegates.
Posted on December 22, 2007 by staceyw1
It is not just a talking point because
we want to be difficult. It helps us
reason about what exactly is going on.
To be clear, there is *no such thing
as an anonymous delegate. They don’t
exist (not yet). They are "Anonymous
Methods" – period. It matters in how
we think of them and how we talk about
them. Lets take a look at the
anonymous method statement "delegate()
{…}". This is actually two different
operations and when we think of it
this way, we will never be confused
again. The first thing the compiler
does is create the anonymous method
under the covers using the inferred
delegate signature as the method
signature. It is not correct to say
the method is "unnamed" because it
does have a name and the compiler
assigns it. It is just hidden from
normal view. The next thing it does
is create a delegate object of the
required type to wrap the method. This
is called delegate inference and can
be the source of this confusion. For
this to work, the compiler must be
able to figure out (i.e. infer) what
delegate type it will create. It has
to be a known concrete type. Let
write some code to see why.
private void MyMethod()
{
}
Does not compile:
1) Delegate d = delegate() { }; // Cannot convert anonymous method to type ‘System.Delegate’ because it is not a delegate type
2) Delegate d2 = MyMethod; // Cannot convert method group ‘MyMethod’ to non-delegate type ‘System.Delegate’
3) Delegate d3 = (WaitCallback)MyMethod; // No overload for ‘MyMethod’ matches delegate ‘System.Threading.WaitCallback’
Line 1 does not compile because the
compiler can not infer any delegate
type. It can plainly see the signature
we desire, but there is no concrete
delegate type the compiler can see.
It could create an anonymous type of
type delegate for us, but it does not
work like that. Line 2 does not
compile for a similar reason. Even
though the compiler knows the method
signature, we are not giving it a
delegate type and it is not just going
to pick one that would happen to work
(not what side effects that could
have). Line 3 does not work because
we purposely mismatched the method
signature with a delegate having a
different signature (as WaitCallback
takes and object).
Compiles:
4) Delegate d4 = (MethodInvoker)MyMethod; // Works because we cast to a delegate type of the same signature.
5) Delegate d5 = (Action)delegate { }; // Works for same reason as d4.
6) Action d6 = MyMethod; // Delegate inference at work here. New Action delegate is created and assigned.
In contrast, these work. Line 1 works
because we tell the compiler what
delegate type to use and they match,
so it works. Line 5 works for the
same reason. Note we used the special
form of "delegate" without the parens.
The compiler infers the method
signature from the cast and creates
the anonymous method with the same
signature as the inferred delegate
type. Line 6 works because the
MyMethod() and Action use same
signature.
I hope this helps.
Also see:
http://msdn.microsoft.com/msdnmag/issues/04/05/C20/
What Mark said.
The problem is that Do takes a Delegate parameter. The compiler can't convert the anonymous methods to Delegate, only a "delegate type" i.e. a concrete type derived from Delegate.
If that Do function had took Action<>, Action<,> ... etc. overloads, you wouldn't need the cast.
The problem is not with your delegate definition, it's that the parameter of the Do() method is of type System.Delegate, and the compiler generated delegate type (FakeSave) does not implicitly convert to System.Delegate.
Try adding a cast in front of your anonymous delegate:
Expect.Call(delegate { _dao.Save(t); }).Do((Delegate)delegate { t.Message = "I drink goats blood"; });
Try something like:
Expect.Call(delegate { _dao.Save(t); }).Do(new EventHandler(delegate(Transaction t2) { t2.CheckInInfo.CheckInMessage = "I drink goats blood"; }));
Note the added EventHandler around the delegate.
EDIT: might not work since the function signatures of EventHandler and the delegate are not the same... The solution you added to the bottom of your question may be the only way.
Alternately, you could create a generic delegate type:
public delegate void UnitTestingDelegate<T>(T thing);
So that the delegate is not Transaction specific.

Categories