I have a class that has to receive methods in order to call them as well as doing other executions. These methods have to be used many times and for many different users so the simpler the better.
To deal with this I have two methods:
void Receive(Action func)
{
// Do some things.
func();
}
T Receive<T>(Func<T> func)
{
// Do some things.
return func();
}
(Actually I have 34 methods to be able to receive any of the different Action or Func defined.)
Then, I want to be able to pass any method as a parameter to the Receive function, to be able to do something like this:
void Test()
{
Receive(A);
Receive(B);
}
void A()
{
}
int B()
{
return 0;
}
Just like this, it gives me one error in Receive(B):
The call is ambiguous between the following methods or properties: 'Class1.Receive(System.Action)' and 'Class1.Receive<int>(System.Func<int>)'
Ok, the signature is the same (although no error is shown if I don't use the methods).
If I remove the Receive(Action) method, I get in Receive(A) the following error:
The type arguments for method 'Class1.Receive<T>(System.Func<T>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
But my type in this case is void and it is forbidden to use it as a generic parameter.
So, is there a way to have my Receive method without using any explicit cast of Action or Func?
No you can't do this - void is not a valid return type for Func<T>. The best you could do is to wrap it in a Func<object>:
Receive(() => { A(); return null; });
Try specifying the generic type parameter explicitly:
Receive<int>(B);
Related
I have a piece of code that currently looks like this:
Signature of the Subscribe method:
void Subscribe<T, TResult>(Func<T, TResult> action);
class Service {
int methodThatRequiresIntAndReturnsInt(int i) => i * 2;
}
In my mind it should be possible to extrapolate what the types for T and TReturn when trying to use the subscribe method, however compiler tells me that the types cannot be inferred from usage, meaning i end up writing this code:
Queue.Subscribe<int, int>(Service.methodThatRequiresIntAndReturnsInt);
My question is whether it is possible and if so how should the method signature/usage look so that it would be possible to use it without type hinting e.g.:
Queue.Subscribe(input => input * 2);
Current implementation is along the lines of this:
_commandSubscription.Subscribe<CreateUpdateCommand, bool>(Resolve<UpdateService>().CreateUpdate);
_commandSubscription.Subscribe<AddCommentCommand>(Resolve<UpdateService>().AddComment);
The implementations for the service methods are as follows:
public class UpdateService {
public void AddComment(AddCommentCommand command) {
// DO STUFF
}
public bool CreateUpdate(CreateUpdateCommand command) {
// Do stuff
return true;
}
}
You could do the following:
Queue.Subscribe((int i) => Service.methodThatRequiresIntAndReturnsInt(i));
In practice the subcribed function works equivalently and you avoid explicitly typing all generic arguments.
Why does the first call to Foo below compile but the second one results in an ambiguous invocation compiler error?
(using c# 7.2)
private static void AmbiguousAsyncOverload() {
Foo(() => Bar()); // This is OK
//Foo(Bar); // Error, ambiguous overload
}
private static void Foo(Func<int> func) {
func();
}
private static void Foo(Func<string> func) {
func();
}
private static int Bar() {
return 4;
}
If I remove the first (Func<int>) implementation of Foo, and hence the possibility of ambiguity, then the compiler (correctly) reports that Bar doesn't have the correct signature to be passed into Foo, which implies it has enough information to resolve the ambiguity.
I would understand if the compiler didn't look at return values during overload resolution and therefore both calls failed, but my question is why does one call compile ok while the other doesn't.
This was an issue for all versions of C# up until it was fixed in v7.3. Return types were not taken into account during overload resolution. From the release notes (or the language proposal) for C# 7.3:
For a method group conversion, candidate methods whose return type doesn't match up with the delegate's return type are removed from the set.
How does the Action delegate with custom classes work when i am not explicitly passing the input parameter type of the referenced method :
DirectMethodCall.PassMethod(x=>x.NoReturnOneParameterMethod(1));
public static void PassMethod(Action<NewClass> c)
{
NewClass op = new NewClass();
c(op);
}
Why do i need to pass the "op" to the Action delegate ?
As comments are a bit messy to post code examples, I'll continue here.
You are not repeating code, you're misunderstanding what you've actually coded. public static void PassMethod(Action<NewClass> c) means
PassMethod requires, as a parameter, a method which executes on a NewClass object.
Maybe this makes it more clear:
void Main()
{
//I am defining the implementation of a method which requires as integer as a parameter, but I don't actually invoke it, just define it.
ExecuteMethod(i => Console.WriteLine(i));
}
public static void ExecuteMethod(Action<int> method)
{
//I don't know what method does, all I know is that I am running it with the number 5.
method(5);
}
ExecuteMethod Takes a method which requires an integer. It doesn't know what the method does. All it knows is that it requires an int, and it passes it the value 5
The actual code is from the caller:
i => Console.WriteLine(i)
Here, i is set to 5, and so the result is 5 being printed to the console.
Your PassMethod is expecting a delegate which accepts one parameter of type NewClass and it calls NoReturnOneParameterMethod() with parameter 1 and has a return type of void
Action<T> means it is a delegate that takes type T as its argument and has return type of void.
See: MSDN Action
I need to be able to pass an arbitrary method to some function myFunction:
void myFunction(AnyFunc func) { ... }
It should be possible to execute it with other static, instance, public or private methods or even delegates:
myFunction(SomeClass.PublicStaticMethod);
myFunction(SomeObject.PrivateInstanceMethod);
myFunction(delegate(int x) { return 5*x; });
Passed method may have any number of parameters and any return type. It should also be possible to learn the actual number of parameters and their types in myFunction via reflection. What would be AnyFunc in the myFunction definition to accommodate such requirements? It is acceptible to have several overloaded versions of the myFunction.
The Delegate type is the supertype of all other delegate types:
void myFunction(Delegate func) { ... }
Then, func.Method will give you a MethodInfo object you can use to inspect the return type and parameter types.
When calling the function you will have to explicitly specify which type of delegate you want to create:
myFunction((Func<int, int>) delegate (int x) { return 5 * x; });
Some idea of what you're trying to accomplish at a higher level would be good, as this approach may not turn out to be ideal.
Have the method accept a Delegate, rather than a particular delegate:
void myFunction(Delegate func)
{
}
I'm trying to think of a nice way to call ANY type of function. void or return value, no params or many. i need to time the execution of this function and wish to hide away all this from the client. so i just want to give the client code a way to use my class to call any type of function, then my class will execute it and time it, then return back to the client.
the part i can't figure out is how to support any type of function. delegates need a type. func needs a return. i want somethign generic that will make the client do minimal amount of work to setup the params, and minimal amount of work to get the return value (if any).
is this possible without reflection? performance is very important here.
I can imagine client code looking like this:
Recorder r = new Recorder();
r.Params.Add(param);
r.Params.Add(param);
r.CallFunc([function]);
MyReturnType ret = (MyReturnType)r.returnValue;
does that seem doable?
There's a widely used way to wrap method calls:
public static class Recorder
{
// overload for any method, that returns value
public static T CallFunc(Func<T> func)
{
// other stuff here
return func();
// other stuff here
}
// overload for any method, that returns void
public static CallFunc(Action action)
{
// other stuff here
action();
// other stuff here
}
}
Usage:
Recorder.CallFunc(() => someObj.SomeMethod(param1, param2));
You could just overload your method.
void MyMetaFunction(Action action);
void MyMetaFunction<T>(Action<T> action, T arg);
TResult MyMetaFunction<TResult>(Func<TResult> func);
TResult MyMetaFunction<TResult,TArg>(Func<TResult,TArg> func, TArg arg);
And so forth. Of course, this does put some limit on the number of arguments you can support, but maybe that is still ok for you.
Based on your expectations and pseudocode, you can do something like this.
public void SomeMethod(params object[] objects) {
}
public void SomeMethod(out object returnValue, params object[] objects) {
}
This supports both any number, and any type of arguments, and can return a value or not return a value depending on the overload the client chooses. But I have to say, this seems like a really bad idea, and you will be responsible for handling anything that's passed in as an argument.