How to pass a method as a Delegate the short way? - c#

I have a my method X that invokes method Y that I want to be passed as a parameter.
The challenge is the Y can virtually be any method, but in my specific case it can be an Action, Func<bool> or Func<int?>. Here's receiving end:
void X(Delegate y) {
if (y is Action action) { /* ... */ }
else if (y is Func<bool> boolFunction) { /* ... */ }
else if (y if Func<int?> intFunction) { /* ... */ }
else throw new NotImplementedException();
// do the other stuff depending on `y`
}
Using this as:
X(Y);
doesn't compile and shows:
Error CS1503 Argument 1: cannot convert from 'method group' to 'Delegate'
However, invoking like this:
X(new Action(() => Y()));
works! My problem with this is it looks ugly, involves "useless" boilerplate code, using lambdas to just call method, instead passing method as delegate.
Of course it is solvable by creating 3 different method signatures, accepting Action, Func<bool> and Func<int?> as delegate argument, but again - BOILERPLATE code, repeating code - all the things I want to avoid here.
So what is the succinct an elegant way to solve this in C#?
EDIT: To clarify the question - this is a "code golf" type of a question. There are many, many ways to do what I intend to do, they all work, and I have even a great choice in fast and slow solutions, because in my specific case the performance is not important (it handles user click, and all Reflection calls in the world are way faster than users's mice). I asked the question to improve my advanced C# skills guessing there are some syntax flavors more elegant and matched to the particular challenge. That's the way I learned C# from scratch. You can use callbacks if you don't know "async / await" syntax, you can use loops if you don't know LINQ. You can pass boxed objects if you don't know how to use generics. If there is a specialized language feature to express the idea in a better way - I want to learn it.

The error occurs because you are passing in Y, which could refer to any overload with the name Y. This could be returning an int, passing in a string etc. The compiler doesn't know which overload to use, so it's giving you that error. You just need to tell it what delegate type it is:
X(new Action<int>(Y));
X((Action<int>)Y);
This will require a slight modification to your code, but X<Action<int>>(Y)
(Change your definition of X to
private void X<TDelegate>(TDelegate del) where TDelegate : Delegate
{
if (del is Action action) { /* ... */ }
else if (del is Func<bool> boolFunction) { /* ... */ }
else if (del is Func<int?> intFunction) { /* ... */ }
else throw new NotImplementedException();
// do the other stuff depending on `y`
}
ReSharper actually suggested to convert it to a switch:
private void X<TDelegate>(TDelegate del) where TDelegate : Delegate
{
switch (del)
{
case Action action: /* ... */
break;
case Func<bool> boolFunction: /* ... */
break;
case Func<int?> intFunction: /* ... */
break;
default:
throw new NotImplementedException();
}
// do the other stuff depending on `y`
}
P.S. I believe generic is the most efficient, and X(new Action(()=> Y())) is needlessly verbose and makes the compiler introduce extra functions. If you have to use it, simplify it to X(new Action(Y))

A solution with one overload method :
class Program
{
static void Main(string[] args)
{
InvokeMethod(MethodVoid);
InvokeMethod(MethodBool);
InvokeMethod(MethodInt);
}
public static void InvokeMethod(Action x)
{
x.Invoke();
}
public static void InvokeMethod<T>(Func<T> x)
{
InvokeMethod(() => x());
}
public static void MethodVoid()
{
}
public static bool MethodBool()
{
return true;
}
public static int? MethodInt()
{
return 42;
}
}

Related

Passing argument to an Action without using an anonymous function?

Is there a way I can pass through an argument to an Action without using an anonymous function?
Eg, the following code works fine:
private void doSomethingAndLogIt(string log, Action dosomething)
{
Debug.WriteLine(log);
dosomething();
}
private void multiplyIt()
{
_result = "great";
}
...
doSomethingAndLogIt("Did something", multiplyIt);
but what I want to do is this:
private void doSomethingAndLogIt(string log, Action<int> dosomething)
{
Debug.WriteLine(log);
dosomething(???);
}
private void multiplyIt(int a)
{
_result = "great";
}
doSomethingAndLogIt("Did something", multiplyIt(5));
I realise that I can do this:
private void doSomethingAndLogIt(string log, Action<int> dosomething, int inputValue)
{
Debug.WriteLine(log);
dosomething(inputValue);
}
private void multiplyIt(int a)
{
_result = "great";
}
doSomethingAndLogIt("Did something", multiplyIt, 5);
but it's pretty confusing. I also realise that I can do this:
doSomethingAndLogIt("Did something", () => {
multiplyIt(5);
});
but it would be great if I could do this:
doSomethingAndLogIt("Did something", multiplyIt(5));
You do not need to do anything special. This code below:
doSomethingAndLogIt("Test", () => multiplyIt(5));
will already do what you are after. When the delegate is called, the parameter 5 will be passed in as well. Why? Because the callee will call your delegate, and you will call the method multiply with the argument 5.
Here is a quick test.
It isn't possible to do that as of the current version of C#, here's why...
Let's take your example (fake syntax)
public int MultiplyIt(int value)
{
//Do something that has side-effects
}
public void SomeMethod(Action<int> someAction<int>)
{
//Do something
someAction();
}
Now let's create an override of that method:
public void SomeMethod(int someValue)
{
//Do something
}
Now you call it:
SomeMethod(multiplyIt(5))
Which one does the compiler call?
Lets say you don't overload it (or that for some reason the compiler shouts an error if you do, but it is legal).
What then is the difference between these two calls?
SomeMethod(multiplyIt(5));
SomeMethod(() => multiplyIt(5));
Technically the first one runs multiplyIt before passing its value to SomeMethod. The second one multiplyIt may never be called, or it may alter something and then call it. That is an important distinction. If you add in some method to call it without the () => part, the developer can't know, without reading documentation, how the method call (and the action) are called. Is it a normal method call? The "special" delegate case? Who knows.
The () => isn't that much of a price to pay to be able to read a method and understand that you are passing in a delegate vs a value.

Pass type as Type instead of string paramater

I would like to convert this (which is error prone)....
public static void GenerateReport(string report)
{
switch (report)
{
case "ReportA":
// do stuff
break;
case "ReportB":
// do stuff
break;
case "ReportC":
// do stuff
break;
}
}
To this....
public static void GenerateReport<T>()
{
switch (T) // BUT.... how do I handle this?
{
case ReportA:
// do stuff
break;
case ReportB:
// do stuff
break;
case ReportC:
// do stuff
break;
}
}
I have seen a LOT of questions that ask almost the same thing, but none of them have led me to an answer. Like this one, but for me, the solution provided in that thread flat out doesn't work. It throws multiple syntax errors when I try to compile. the solution there says:
switch typeof(T) {
//
}
You don't need generics for that, nor a switch statement with type detecting... instead use method overloading for each of the types and keep the do stuff pieces in their own methods...
public static void GenerateReport(ReportA a) { /*do stuff*/ }
public static void GenerateReport(ReportB b) { /*do stuff*/ }
public static void GenerateReport(ReportC c) { /*do stuff*/ }
Whenever you have if/switch statements where the code will execute differently depending on the input but produce generic output like what you have in your question it is usually a sign that you need to look into doing some refactoring.
In this case the best option would be to use an interface based design and move the logic for executing the various reports into their own types. This will allow you to better manage additional reports on an as needed basis without having to touch the existing code.
public interface IReporter {
void GenerateReport();
}
public class ReporterA : IReporter {
public void GenerateReport() { /* execute report */}
}
public class ReporterB : IReporter {
public void GenerateReport() { /* execute report */}
}
public class ReporterC : IReporter {
public void GenerateReport() { /* execute report */}
}
// The responsibilty of the factory is only to create the correct reporter based on the request
public class ReporterFactory{
public IReporter CreateReporter(string input){
/* the logic here can vary, you can get creative with Attributes
and name each report type and use reflection to create the
correct report type. You can also use an Enum and use that as an attribute value over
each Reporter type. There are many ways to handle it.
*/
}
}
/* your refactored method */
public static void GenerateReport(string report)
{
/* again, creation pattern could be based on something other than a string. It depends on how you want to differentiate your reporters*/
var reporter = new ReporterFactory().CreateReporter(report);
reporter.GenerateReport();
}
The key point about generics is that if the thing you are doing isn't roughly the same for each final T, then it isn't actually generic and you shouldn't be doing it that way.
Good candidates here might include:
an enum
polymorphism (a virtual / abstract method)
passing in a Type instance
but... not generics. The reason the language isn't helping you is because this isn't a good fit. That said: you could do:
if(typeof(T) == typeof(Foo)) {
// foo
} else if (typeof(T) == typeof(Bar)) {
// bar
} ...
but; that is kinda missing the point of generics.
You can do it like this:
public static void RunIfEqual<TLeft, TRight>(Action action)
{
if (typeof(TLeft) == typeof(TRight))
{
action();
}
}
...
RunIfEqual<T, ReportA>(()=> ...);
RunIfEqual<T, ReportB>(()=> ...);
RunIfEqual<T, ReportC>(()=> ...);
Or even better way, you can define some ReportGeneratorFactory, that will choose which generator to use for this type and return it to you. Then you can just call GenerateReport on it.

My overloaded generic method is not called

I write this piece of code in one of my C# project:
public static class GetAppendReceiver
{
public static AppendReceiver<DataType> Get<DataType>(AppendReceiver<DataType>.DataProcessor processor0, int delayIn = 0)
{
throw new InvalidOperationException();
}
public static AppendReceiver<string> Get(AppendReceiver<string>.DataProcessor processor0, int delayIn = 0)
{
return new StringAppendReceiver(processor0, delayIn);
}
}
public abstract class AppendReceiver<DataType>
{
public delegate void DataProcessor(DataType data);
...
}
AppendReceiver<DataType> is an Abstract class, DataProcessor is a delegate type.
When calling GetAppendReceiver.Get with a string DataProcessor I expect the overloaded function to be called, but I get the InvalidOperationException.
Here is my call:
class ClassA<DataType>
{
public void RegisterAppendReceiver(AppendReceiver<DataType>.DataProcessor receiver)
{
appendReceivers.Add(GetAppendReceiver.Get(receiver, Delay));
}
}
Example of RegisterAppendReceiver call:
myObject.RegisterAppendReceiver(myMethod);
Where myMethod is defined like this:
public void writeMessage(string strMessageIn)
My question is why I get the wrong overload called, and how can I force the language to call the overload I want ?
Thanks for your help !
Eric Lippert answers this question concisely in his article Generics are not Templates
I don't want to copy the entire article. So the relevant point is this:
We do the overload resolution once and bake in the result.
So the C# compiler decides, at the time it compiles RegisterAppendReceiver, which overload of "GetAppendReceiver.Get" it is going to call. Since, at that point, the only thing it knows about DataType is that DataType can be anything at all, it compiles in the call to the overload that takes an AppendReceiver.DataProcessor, not an AppendReceiver.DataProcessor.
By comparison, the C++ compiler does not behave this way. Each and every time a generic call is made, the compiler does the substitution over again. This is one reason C++ compilers are much slower than C# compilers.

How does adding a break in a while loop resolve overload ambiguity?

Consider this Reactive Extensions snippet (ignore the practicality of it):
return Observable.Create<string>(async observable =>
{
while (true)
{
}
});
This does not compile with Reactive Extensions 2.2.5 (using NuGet Rx-Main package). It fails with:
Error 1 The call is ambiguous between the following methods or properties: 'System.Reactive.Linq.Observable.Create<string>(System.Func<System.IObserver<string>,System.Threading.Tasks.Task<System.Action>>)' and 'System.Reactive.Linq.Observable.Create<string>(System.Func<System.IObserver<string>,System.Threading.Tasks.Task>)'
However, adding a break anywhere in the while loop fixes the compilation error:
return Observable.Create<string>(async observable =>
{
while (true)
{
break;
}
});
The problem can be reproduced without Reactive Extensions at all (easier if you want to try it without fiddling with Rx):
class Program
{
static void Main(string[] args)
{
Observable.Create<string>(async blah =>
{
while (true)
{
Console.WriteLine("foo.");
break; //Remove this and the compiler will break
}
});
}
}
public class Observable
{
public static IObservable<TResult> Create<TResult>(Func<IObserver<TResult>, Task> subscribeAsync)
{
throw new Exception("Impl not important.");
}
public static IObservable<TResult> Create<TResult>(Func<IObserver<TResult>, Task<Action>> subscribeAsync)
{
throw new Exception("Impl not important.");
}
}
public interface IObserver<T>
{
}
Ignoring the Reactive Extensions part of it, Why does adding break help the C# compiler resolve the ambiguity? How can this be described with the rules of overload resolution from the C# specification?
I'm using Visual Studio 2013 Update 2 targeting 4.5.1.
It's easiest to just pull out async as well as the lambdas here, as it emphasizes what's going on. Both of these methods are valid and will compile:
public static void Foo()
{
while (true) { }
}
public static Action Foo()
{
while (true) { }
}
However, for these two methods:
public static void Foo()
{
while (true) { break; }
}
public static Action Foo()
{
while (true) { break; }
}
The first compiles, and the second does not. It has a code path that doesn't return a valid value.
In fact, while(true){} (along with throw new Exception();) is an interesting statement in that it is the valid body of a method with any return type.
Since the infinite loop is a suitable candidate for both overloads, and neither overload is "better", it results in an ambiguity error. The non-infinite loop implementation only has one suitable candidate in overload resolution, so it compiles.
Of course, to bring async back into play, it is actually relevant in one way here. For the async methods they both always return something, whether it's a Task or a Task<T>. The "betterness" algorithms for overload resolution will prefer delegates that return a value over void delegates when there is a lambda that could match either, however in your case the two overload both have delegates that return a value, the fact that for async methods returning a Task instead of a Task<T> is the conceptual equivalent of not returning a value isn't incorporated into that betterness algorithm. Because of this the non-async equivalent wouldn't result in an ambiguity error, even though both overloads are applicable.
Of course it's worth noting that writing a program to determine if an arbitrary block of code will ever complete is a famously unsolvable problem, however, while the compiler cannot correctly evaluate whether every single snippet will complete, it can prove, in certain simple cases such as this one, that the code will in fact never complete. Because of this there are ways of writing code that will clearly (to you and me) never complete, but that the compiler will treat as possibly completing.
Leaving async out of this to start with...
With the break, the end of the lambda expression is reachable, therefore the return type of the lambda has to be void.
Without the break, the end of the lambda expression is unreachable, so any return type would be valid. For example, this is fine:
Func<string> foo = () => { while(true); };
whereas this isn't:
Func<string> foo = () => { while(true) { break; } };
So without the break, the lambda expression would be convertible to any delegate type with a single parameter. With the break, the lambda expression is only convertible to a delegate type with a single parameter and a return type of void.
Add the async part and void becomes void or Task, vs void, Task or Task<T> for any T where previously you could have any return type. For example:
// Valid
Func<Task<string>> foo = async () => { while(true); };
// Invalid (it doesn't actually return a string)
Func<Task<string>> foo = async () => { while(true) { break; } };
// Valid
Func<Task> foo = async () => { while(true) { break; } };
// Valid
Action foo = async () => { while(true) { break; } };

c# .net why does Task.Run seem to handle Func<T> differently than other code?

The new Task.Run static method that's part of .NET 4.5 doesn't seem to behave as one might expect.
For example:
Task<Int32> t = Task.Run(()=>5);
compiles fine, but
Task<Int32> t = Task.Run(MyIntReturningMethod);
...
public Int32 MyIntReturningMethod() {
return (5);
}
complains that MyIntReturningMethod is returning the wrong type.
Perhaps I am just not understanding which overload of Task.Run is being called. But in my mind, my lambda code above looks a lot like a Func<Int32>, and MyIntReturningMethod is definitely compatible with Func<Int32>
Any ideas of what's going on?
Michael
(Of course, to get out of the problem, simply say Task.Run((Func<int>)MyIntReturningMethod).)
This has absolutely nothing to do with Task and so on.
One problem to be aware of here is that when very many overloads are present, the compiler error text will focus on just one "pair" of overloads. So that is confusing. The reason is that the algorithm to determine the best overload considers all overloads, and when that algorithm concludes that no best overload can be found, that does not produce a certain pair of overloads for the error text because all overloads may (or may not) have been involved.
To understand what happens, see instead this simplified version:
static class Program
{
static void Main()
{
Run(() => 5); // compiles, goes to generic overload
Run(M); // won't compile!
}
static void Run(Action a)
{
}
static void Run<T>(Func<T> f)
{
}
static int M()
{
return 5;
}
}
As we see, this has absolutely no reference to Task, but still produces the same problem.
Note that anonymous function conversions and method group conversions are (still) not the exact same thing. Details are to be found in the C# Language Specification.
The lambda:
() => 5
is actually not even convertible to the System.Action type. If you try to do:
Action myLittleVariable = () => 5;
it will fail with error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement. So it is really clear which overload to use with the lambda.
On the other hand, the method group:
M
is convertible to both Func<int> and Action. Remember that it is perfectly allowed to not pick up a return value, just like the statement:
M(); // don't use return value
is valid by itself.
This sort-of answers the question but I will give an extra example to make an additional point. Consider the example:
static class Program
{
static void Main()
{
Run(() => int.Parse("5")); // compiles!
}
static void Run(Action a)
{
}
static void Run<T>(Func<T> f)
{
}
}
In this last example, the lambda is actually convertible to both delegate types! (Just try to remove the generic overload.) For the right-hand-side of the lambda arrow => is an expression:
int.Parse("5")
which is valid as a statement by itself. But overload resolution can still find a better overload in this case. As I said earlier, check the C# Spec.
Inspired by HansPassant and BlueRaja-DannyPflughoeft, here is one final (I think) example:
class Program
{
static void Main()
{
Run(M); // won't compile!
}
static void Run(Func<int> f)
{
}
static void Run(Func<FileStream> f)
{
}
static int M()
{
return 5;
}
}
Note that in this case, there is absolutely no way the int 5 could be converted into a System.IO.FileStream. Still the method group conversion fails. This might be related to the fact the with two ordinary methods int f(); and FileStream f();, for example inherited by some interface from two different base interfaces, there is no way to resolve the call f();. The return type is not part of a method's signature in C#.
I still avoid to introduce Task in my answer since it could give a wrong impression of what this problem is about. People have a hard time understanding Task, and it is relatively new in the BCL.
This answer has evolved a lot. In the end, it turns out that this is really the same underlying problem as in the thread Why is Func<T> ambiguous with Func<IEnumerable<T>>?. My example with Func<int> and Func<FileStream> is almost as clear. Eric Lippert gives a good answer in that other thread.
This was supposed to be fixed in .Net 4.0, but Task.Run() is new to .Net 4.5
.NET 4.5 has its own overload ambiguity by adding the Task.Run(Func<Task<T>>) method. And the support for async/await in C# version 5. Which permits an implicit conversion from T foo() to Func<Task<T>>.
That's syntax sugar that's pretty sweet for async/await but produces cavities here. The omission of the async keyword on the method declaration is not considered in the method overload selection, that opens another pandora box of misery with programmers forgetting to use async when they meant to. Otherwise follows the usual C# convention that only the method name and arguments in the method signature is considered for method overload selection.
Using the delegate type explicitly is required to resolve the ambiguity.
When you pass a Func<TResult> into a method Run<TResult>(Func<TResult>) you don't have to specify the generic on the methodcall because it can infer it. Your lambda does that inference.
However, your function is not actually a Func<TResult> whereas the lambda was.
If you do Func<Int32> f = MyIntReturningMethod it works. Now if you specify Task.Run<Int32>(MyIntReturningMethod) you would expect it to work also. However it can't decide if it should resolve the Func<Task<TResult>> overload or the Func<TResult> overload, and that doesn't make much sense because its obvious that the method is not returning a task.
If you compile something simple like follows:
void Main()
{
Thing(MyIntReturningMethod);
}
public void Thing<T>(Func<T> o)
{
o();
}
public Int32 MyIntReturningMethod()
{
return (5);
}
the IL looks like this....
IL_0001: ldarg.0
IL_0002: ldarg.0
IL_0003: ldftn UserQuery.MyIntReturningMethod
IL_0009: newobj System.Func<System.Int32>..ctor
IL_000E: call UserQuery.Thing
(Some of the extra stuff is from LINQ Pad's additions... like the UserQuery part)
The IL looks identical as if you do an explicit cast. So it seems like the compiler does't actually know which method to use. So it doesn't know what cast to create automatically.
You can just use Task.Run<Int32>((Func<Int32>)MyIntReturningMethod) to help it out a bit. Though I do agree that this seems like something the compiler should be able to handle. Because Func<Task<Int32>> is not the same as Func<Int32>, so it doesn't make sense that they would confuse the compiler.
Seems like an overload resolution problem. The compiler can't tell which overload you're calling (because first it has to find the correct delegate to create, which it doesn't know because that depends on the overload you're calling). It would have to guess-and-check but I'm guessing it's not that smart.
The approach of Tyler Jensen works for me.
Also, you can try this using a lambda expression:
public class MyTest
{
public void RunTest()
{
Task<Int32> t = Task.Run<Int32>(() => MyIntReturningMethod());
t.Wait();
Console.WriteLine(t.Result);
}
public int MyIntReturningMethod()
{
return (5);
}
}
Here's my stab at it:
public class MyTest
{
public void RunTest()
{
Task<Int32> t = Task.Run<Int32>(new Func<int>(MyIntReturningMethod));
t.Wait();
Console.WriteLine(t.Result);
}
public int MyIntReturningMethod()
{
return (5);
}
}

Categories

Resources