895

I have several methods all with the same parameter types and return values but different names and blocks. I want to pass the name of the method to run to another method that will invoke the passed method.

public int Method1(string)
{
    // Do something
    return myInt;
}

public int Method2(string)
{
    // Do something different
    return myInt;
}

public bool RunTheMethod([Method Name passed in here] myMethodName)
{
    // Do stuff
    int i = myMethodName("My String");
    // Do more stuff
    return true;
}

public bool Test()
{
    return RunTheMethod(Method1);
}

This code does not work but this is what I am trying to do. What I don't understand is how to write the RunTheMethod code since I need to define the parameter.

Davide Cannizzo
  • 2,826
  • 1
  • 29
  • 31
user31673
  • 13,245
  • 12
  • 58
  • 96
  • 14
    Why don't you pass a delegate instead of the name of the method? – Mark Byers Jan 17 '10 at 21:02
  • The question claims method signature is about parameters and return values, when it really comprises parameter types and method name. Return type doesn't matter, indeed you cannot declare two methods that only differ from return types. In contrast, you can declare methods whose only name is different. I've just edited your question to fix this and some other things. – Davide Cannizzo Aug 23 '20 at 13:01

13 Answers13

1039

You can use the Func delegate in .NET 3.5 as the parameter in your RunTheMethod method. The Func delegate allows you to specify a method that takes a number of parameters of a specific type and returns a single argument of a specific type. Here is an example that should work:

public class Class1
{
    public int Method1(string input)
    {
        //... do something
        return 0;
    }

    public int Method2(string input)
    {
        //... do something different
        return 1;
    }

    public bool RunTheMethod(Func<string, int> myMethodName)
    {
        //... do stuff
        int i = myMethodName("My String");
        //... do more stuff
        return true;
    }

    public bool Test()
    {
        return RunTheMethod(Method1);
    }
}
Davide Cannizzo
  • 2,826
  • 1
  • 29
  • 31
Egil Hansen
  • 15,028
  • 8
  • 37
  • 54
  • 73
    How would the Func call change if the Method has as signature of returning void and no parameters? I can't seem to get the syntax to work. – user31673 Jan 17 '10 at 21:38
  • 264
    @unknown: In that case it would be `Action` instead of `Func`. – Jon Skeet Jan 17 '10 at 21:45
  • 15
    but now what if you want to pass in arguments to the method?? – john k Feb 24 '14 at 02:28
  • 54
    @user396483 For example, `Action` corresponds to a method which is taking 2 parameters (int and string) and returning void. – serdar Jun 12 '14 at 10:30
  • 1
    @serdar just to complete this: Is it possible to have different param types and a return type different than void? – Noel Widmer Sep 10 '14 at 11:29
  • 32
    @NoelWidmer Using `Func` corresponds to a method which takes 2 parameters (`double` and `string`) and returning `int`. Last specified type is the return type. You can use this delegate for up to 16 parameters. If you somehow need more, write your own delegate as `public delegate TResult Func(T1 arg1, T2 arg2, ..., Tn argn);`. Please correct me if I misunderstood. – serdar Sep 11 '14 at 06:43
  • 1
    @sedar Oh wow, I thought Func<> could only take 2 args. Well that's nice. Thanks' a lot! – Noel Widmer Sep 11 '14 at 07:23
  • 4
    Ever heard of OOP? Pass an object as second parameter, please. – seveves Sep 15 '15 at 13:46
  • 1
    "up" for non ambiguous datatypes in the simple example – granadaCoder May 13 '16 at 20:35
  • And what happens if you want to call RunTheMethod from another class? In this example, you call it from the same class where methods are. – Willy May 09 '17 at 09:23
  • The real question is how do you define a default function as the input. For example `Int.Parse` – Worthy7 Jun 08 '18 at 01:30
  • @user31673 @serdar `Action` is one solution but it requires you explicitly provide an Action overload just for those return `Void`. In FP, it would better be `Unit`(a default `ValueTuple` in C#), which is especially useful in functional programming. FP library like [language-ext](https://github.com/louthy/language-ext#void-isnt-a-real-type) has implemented such idea. This is not a direct answer but it's good to know. – joe Jul 29 '19 at 07:17
  • 1
    @user31673 try this: ```public delegate TResult Func(T1 arg1, T2 arg2, ..., Tn argN);``` – Bojidar Stanchev Aug 28 '19 at 11:14
425

You need to use a delegate. In this case all your methods take a string parameter and return an int - this is most simply represented by the Func<string, int> delegate1. So your code can become correct with as simple a change as this:

public bool RunTheMethod(Func<string, int> myMethodName)
{
    // ... do stuff
    int i = myMethodName("My String");
    // ... do more stuff
    return true;
}

Delegates have a lot more power than this, admittedly. For example, with C# you can create a delegate from a lambda expression, so you could invoke your method this way:

RunTheMethod(x => x.Length);

That will create an anonymous function like this:

// The <> in the name make it "unspeakable" - you can't refer to this method directly
// in your own code.
private static int <>_HiddenMethod_<>(string x)
{
    return x.Length;
}

and then pass that delegate to the RunTheMethod method.

You can use delegates for event subscriptions, asynchronous execution, callbacks - all kinds of things. It's well worth reading up on them, particularly if you want to use LINQ. I have an article which is mostly about the differences between delegates and events, but you may find it useful anyway.


1 This is just based on the generic Func<T, TResult> delegate type in the framework; you could easily declare your own:

public delegate int MyDelegateType(string value)

and then make the parameter be of type MyDelegateType instead.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 79
    +1 This really is an amazing answer to rattle off in two minutes. – David Hall Jan 17 '10 at 21:09
  • 3
    While you can pass the function using delegates, a more traditional OO approach would be to use the strategy pattern. – Paolo Jan 17 '10 at 21:14
  • 25
    @Paolo: Delegates are just a very convenient implementation of the strategy pattern where the strategy in question only requires a single method. It's not like this is going *against* the strategy pattern - but it's a heck of a lot more convenient than implementing the pattern using interfaces. – Jon Skeet Jan 17 '10 at 21:18
  • 5
    Are the "classic" delegates (as known from .NET 1/2) still useful, or are they completely obsolete because of Func/Action? Also, isn't there a delegate keyword missing in your example `public **delegate** int MyDelegateType(string value)`? – M4N Jan 17 '10 at 23:28
  • 1
    @Martin: Doh! Thanks for the fix. Edited. As for declaring your own delegates - it can be useful to give the type name some meaning, but I've rarely created my own delegate type since .NET 3.5. – Jon Skeet Jan 17 '10 at 23:50
  • @DavidHall Rattled off in one minute. Not even two. Incredible. – Robino Dec 24 '14 at 13:32
  • 1
    @Robino: Almost certainly a quick answer to start with, elaborated within the 5 minute grace window. Would love to be able to answer that quickly, but I doubt it happened that way... – Jon Skeet Dec 24 '14 at 13:39
  • 1
    @JonSkeet Ahh, the grace window. So you still might be human. Merry Christmas btw. – Robino Dec 24 '14 at 16:28
  • What is the difference between Func and Action? The first doesn't seem to allow delegates with no arguments. But is that all? – Radu Simionescu Oct 30 '15 at 08:17
  • 2
    @RaduSimionescu: Um, no - a `Func` takes a `T` and returns a `TResult`. An `Action` doesn't take anything and doesn't return anything. – Jon Skeet Oct 30 '15 at 08:22
  • @JonSkeet yes, there's Action<> for that. My question stands. What's the dif between Action<> and Func? – Radu Simionescu Oct 30 '15 at 09:13
  • 3
    @RaduSimionescu: Ah. You weren't clear - you specifically asked about `Func` and `Action`, rather than the *groups* of `Func` and `Action` delegates. But no, the difference isn't about inputs - it's about *outputs*. The `Func` delegates all have a return type (which is one of the type parameters). The `Action` delegates are all `void`. – Jon Skeet Oct 30 '15 at 09:16
  • 4
    @JonSkeet: First, fantastic write-up. Humble suggestion for an edit: when I read the part where you translate the lambda into an anonymous function, and saw this: private static int <>_HiddenMethod_<>(string x) { ... } I was pretty confused for a minute, because <> is used for generics, of course. I spent a few minutes pasting this in C# to see if I was missing something, and then realized you were probably just marking the dynamic part. Changing this might smooth that down for others. Learned a lot from this, thanks! – Brian MacKay Aug 12 '16 at 13:13
  • 1
    What if I want to make my function generic - it should accept functions with any return type and any number of parameters? – sydd Sep 25 '16 at 22:41
  • 2
    @BrianMacKay: It's written that way because the compiler uses names like that for generated members that shouldn't be directly callable. That's what you'll see if you look at the IL. Will add a note though. – Jon Skeet Sep 26 '16 at 05:30
  • 1
    @sydd: It's unclear what you mean at that point, I'm afraid. I suggest you ask a new question, being very precise about your requirements. – Jon Skeet Sep 26 '16 at 05:31
  • @JonSkeet this is what I did, heres the question: http://stackoverflow.com/questions/39692553/passing-a-generic-method-as-a-parameter-in-c-sharp – sydd Sep 26 '16 at 16:44
  • A delegate like `delegate bool ConsoleEventDelegate(int eventType);` is different from `Func`if used with a native DLL function. Delegates are allowed, but template delegates like `SetConsoleCtrlHandler(Func CtrlHandler, bool add)` get a run time failure because they can't be marshaled. – Dietrich Baumgarten Oct 19 '19 at 12:58
  • @DietrichBaumgarten: By "template" do you mean "generic"? I wasn't aware that they couldn't be marshalled for native code. Is this true across all CLR implementations? – Jon Skeet Oct 19 '19 at 17:08
  • Jon, yes I mean of course generic, being more a C++ guy, a generic delegate such as `Func` looked like a template to me... According to https://github.com/dotnet/coreclr/issues/1685 it is true to this day that Marshal can't handle generic types. – Dietrich Baumgarten Oct 20 '19 at 19:29
  • Is there a way I can use this without returning a value. Eg: `RunTheMethod(() => { performSomething...; });` ? – mrid Aug 19 '20 at 09:31
  • @mrid: If you don't want to return anything, you want an `Action` delegate, not a `Func`. – Jon Skeet Aug 19 '20 at 09:34
136

From OP's example:

 public static int Method1(string mystring)
 {
      return 1;
 }

 public static int Method2(string mystring)
 {
     return 2;
 }

You can try Action Delegate! And then call your method using

 public bool RunTheMethod(Action myMethodName)
 {
      myMethodName();   // note: the return value got discarded
      return true;
 }

RunTheMethod(() => Method1("MyString1"));

Or

public static object InvokeMethod(Delegate method, params object[] args)
{
     return method.DynamicInvoke(args);
}

Then simply call method

Console.WriteLine(InvokeMethod(new Func<string,int>(Method1), "MyString1"));

Console.WriteLine(InvokeMethod(new Func<string, int>(Method2), "MyString2"));
themefield
  • 3,847
  • 30
  • 32
Zain Ali
  • 15,535
  • 14
  • 95
  • 108
  • 5
    Thanks, this got me where I wanted to go since I wanted a more generic "RunTheMethod" method that would allow for multiple parameters. Btw your first `InvokeMethod` lambda call should be `RunTheMethod` instead – John Jan 27 '12 at 18:26
  • 1
    Like John, this really helped me have a move generic method. Thanks! – ean5533 Nov 06 '12 at 23:39
  • 2
    You made my day ;) Really simple to use and much more flexible than the selected answer IMO. – Irwene Mar 27 '14 at 11:43
  • Is there a way to expand on RunTheMethod(() => Method1("MyString1")); to retrieve a return value? Ideally a generic? – Jay Jul 05 '16 at 16:32
  • if you want to pass parameters be aware of this: https://stackoverflow.com/a/5414539/2736039 – Ultimo_m Jun 12 '18 at 16:50
  • Thanks Zain. Bit old but wanted to give credit for a great answer :D, helped me a lot using a delegate rather than an Action as a Method Parameter. I'm able to pass different types of Action into the delegate and use the DynamicInvoke. Life Saver – rmail2006 Dec 29 '19 at 20:56
66

In order to provide a clear and complete answer, I'm going to start from the very beginning before showing three possible solutions.


A brief introduction

All .NET languages (such as C#, F#, and Visual Basic) run on top of the Common Language Runtime (CLR), which is a VM that runs code in the Common Intermediate Language (CIL), which is way higher level than machine code. It follows that methods aren't Assembly subroutines, nor are they values, unlike functional languages and JavaScript; rather, they're symbols that CLR recognizes. Not being values, they cannot be passed as a parameter. That's why there's a special tool in .NET. That is, delegates.


What's a delegate?

A delegate represents a handle to a method (the term handle is to be preferred over pointer as the latter would be an implementation detail). Since a method is not a value, there has to be a special class in .NET, namely Delegate, which wraps up any method. What makes it special is that, like very few classes, it needs to be implemented by the CLR itself and couldn't be simply written as a class in a .NET language.


Three different solutions, the same underlying concept

  • The type–unsafe way

    Using the Delegate special class directly.

    Example:

    static void MyMethod()
    {
        Console.WriteLine("I was called by the Delegate special class!");
    }
    
    static void CallAnyMethod(Delegate yourMethod)
    {
        yourMethod.DynamicInvoke(new object[] { /*Array of arguments to pass*/ });
    }
    
    static void Main()
    {
        CallAnyMethod(MyMethod);
    }
    

    The drawback here is your code being type–unsafe, allowing arguments to be passed dynamically, with no constraints.

  • The custom way

    Besides the Delegate special class, the concept of delegates spreads to custom delegates, which are declarations of methods preceded by the delegate keyword. They are type–checked the same way as “normal” method invocations, making for type-safe code.

    Example:

    delegate void PrintDelegate(string prompt);
    
    static void PrintSomewhere(PrintDelegate print, string prompt)
    {
        print(prompt);
    }
    
    static void PrintOnConsole(string prompt)
    {
        Console.WriteLine(prompt);
    }
    
    static void PrintOnScreen(string prompt)
    {
        MessageBox.Show(prompt);
    }
    
    static void Main()
    {
        PrintSomewhere(PrintOnConsole, "Press a key to get a message");
        Console.Read();
        PrintSomewhere(PrintOnScreen, "Hello world");
    }
    
  • The standard library's way

    Alternatively, you can stick with a delegate that's part of the .NET Standard:

    • Action wraps up a parameterless void method;
    • Action<T1> wraps up a void method with one parameter of type T1;
    • Action<T1, T2> wraps up a void method with two parameters of types T1 and T2, respectively,
    • and so forth;
    • Func<TR> wraps up a parameterless function with TR return type;
    • Func<T1, TR> wraps up a function with TR return type and with one parameter of type T1;
    • Func<T1, T2, TR> wraps up a function with TR return type and with two parameters of types T1 and T2, respectively;
    • and so forth.

    However, bear in mind that by using predefined delegates like these, parameter names won't be self-describing, nor is the name of the delegate type meaningful as to what instances are supposed to do. Therefore, refrain from using them in contexts where their purpose is not absolutely self-evident.

The latter solution is the one most people posted. I'm also mentioning it in my answer for the sake of completeness.

Davide Cannizzo
  • 2,826
  • 1
  • 29
  • 31
39

The solution involves Delegates, which are used to store methods to call. Define a method taking a delegate as an argument,

public static T Runner<T>(Func<T> funcToRun)
{
    // Do stuff before running function as normal
    return funcToRun();
}

Then pass the delegate on the call site:

var returnValue = Runner(() => GetUser(99));
Davide Cannizzo
  • 2,826
  • 1
  • 29
  • 31
kravits88
  • 12,431
  • 1
  • 51
  • 53
  • 7
    It's very userfully. With this way, can use one or many parameters. I guess, the most updated answer is this. – bafsar Jan 23 '15 at 16:53
  • I'd like to add one thing about this implementation. If the method you are going to pass has return type of void, then you can't use this solution. – Imants Volkovs May 19 '16 at 21:00
  • @ImantsVolkovs I believe you might be able to to modify this to use an Action instead of a Func, and change the signature to void. Not 100% sure though. – Shockwave Mar 27 '17 at 09:37
  • 2
    Is there any way to get the parameters passed to the function that is called? – Jimmy Aug 03 '17 at 20:43
16

You should use a Func<string, int> delegate, that represents a function taking a string argument and returning an int value:

public bool RunTheMethod(Func<string, int> myMethod)
{
    // Do stuff
    myMethod.Invoke("My String");
    // Do stuff
    return true;
}

Then invoke it this way:

public bool Test()
{
    return RunTheMethod(Method1);
}
Davide Cannizzo
  • 2,826
  • 1
  • 29
  • 31
Bruno Reis
  • 37,201
  • 11
  • 119
  • 156
2

Here is an example Which can help you better to understand how to pass a function as a parameter.

Suppose you have Parent page and you want to open a child popup window. In the parent page there is a textbox that should be filled basing on child popup textbox.

Here you need to create a delegate.

Parent.cs // declaration of delegates public delegate void FillName(String FirstName);

Now create a function which will fill your textbox and function should map delegates

//parameters
public void Getname(String ThisName)
{
     txtname.Text=ThisName;
}

Now on button click you need to open a Child popup window.

  private void button1_Click(object sender, RoutedEventArgs e)
  {
        ChildPopUp p = new ChildPopUp (Getname) //pass function name in its constructor

         p.Show();

    }

IN ChildPopUp constructor you need to create parameter of 'delegate type' of parent //page

ChildPopUp.cs

    public  Parent.FillName obj;
    public PopUp(Parent.FillName objTMP)//parameter as deligate type
    {
        obj = objTMP;
        InitializeComponent();
    }



   private void OKButton_Click(object sender, RoutedEventArgs e)
    {


        obj(txtFirstName.Text); 
        // Getname() function will call automatically here
        this.DialogResult = true;
    }
Steak Overflow
  • 7,041
  • 1
  • 37
  • 59
2

While the accepted answer is absolutely correct, I would like to provide an additional method.

I ended up here after doing my own searching for a solution to a similar question. I am building a plugin driven framework, and as part of it I wanted people to be able to add menu items to the applications menu to a generic list without exposing an actual Menu object because the framework may deploy on other platforms that don't have Menu UI objects. Adding general info about the menu is easy enough, but allowing the plugin developer enough liberty to create the callback for when the menu is clicked was proving to be a pain. Until it dawned on me that I was trying to re-invent the wheel and normal menus call and trigger the callback from events!

So the solution, as simple as it sounds once you realize it, eluded me until now.

Just create separate classes for each of your current methods, inherited from a base if you must, and just add an event handler to each.

Wobbles
  • 3,033
  • 1
  • 25
  • 51
2

If you want to pass Method as parameter, use:

using System;

public void Method1()
{
    CallingMethod(CalledMethod);
}

public void CallingMethod(Action method)
{
    method();   // This will call the method that has been passed as parameter
}

public void CalledMethod()
{
    Console.WriteLine("This method is called by passing it as a parameter");
}
Junaid Pathan
  • 3,850
  • 1
  • 25
  • 47
1

If the method passed needs to take one argument and return a value, Func is the best way to go. Here is an example.

public int Method1(string)
{
    // Do something
    return 6;
}

public int Method2(string)
{
    // Do something different
    return 5;
}

public bool RunTheMethod(Func<string, int> myMethodName)
{
    // Do stuff
    int i = myMethodName("My String");
    Console.WriteLine(i); // This is just in place of the "Do more stuff"
    return true;
}

public bool Test()
{
    return RunTheMethod(Method1);
}

Read the docs here

However, if your method that is passed as a parameter does not return anything, you can also use Action. It supports up to 16 paramaters for the passed method. Here is an example.

public int MethodToBeCalled(string name, int age)
{
    Console.WriteLine(name + "'s age is" + age);
}

public bool RunTheMethod(Action<string, int> myMethodName)
{
    // Do stuff
    myMethodName("bob", 32); // Expected output: "bob's age is 32"
    return true;
}

public bool Test()
{
    return RunTheMethod(MethodToBeCalled);
}

Read the documentation here

Caleb Liu
  • 627
  • 5
  • 18
0

Here is an example without a parameter: http://en.csharp-online.net/CSharp_FAQ:_How_call_a_method_using_a_name_string

with params: http://www.daniweb.com/forums/thread98148.html#

you basically pass in an array of objects along with name of method. you then use both with the Invoke method.

params Object[] parameters

Jeremy Samuel
  • 790
  • 6
  • 15
  • Note that the name of the method isn't in a string - it's actually as a method group. Delegates are the best answer here, not reflection. – Jon Skeet Jan 17 '10 at 21:06
  • @Lette: In the method invocation, the expression used as the argument is a *method group*; it's the name of a method which is known at compile-time, and the compiler can convert this into a delegate. This is very different from the situation where the name is only known at execution time. – Jon Skeet Jan 17 '10 at 21:44
  • Do not just paste links. Links must be used as reference, also not omitted. The first link of the answer is broken, if the second one breaks, your answer will become useless. Make it usefull with actual content, the solution should be here, at least the core of it. "params Object[] parameters" is not enough. – fbiazi May 20 '22 at 16:10
0
class PersonDB
{
  string[] list = { "John", "Sam", "Dave" };
  public void Process(ProcessPersonDelegate f)
  {
    foreach(string s in list) f(s);
  }
}

The second class is Client, which will use the storage class. It has a Main method that creates an instance of PersonDB, and it calls that object’s Process method with a method that is defined in the Client class.

class Client
{
  static void Main()
  {
    PersonDB p = new PersonDB();
    p.Process(PrintName);
  }
  static void PrintName(string name)
  {
    System.Console.WriteLine(name);
  }
}
0

I don't know who might need this, but in case you're unsure how to send a lambda with a delegate, when the function using the delegate doesn't need to insert any params in there you just need the return value.

SO you can also do this:

public int DoStuff(string stuff)
{
    Console.WriteLine(stuff);
}

public static bool MethodWithDelegate(Func<int> delegate)
{
    ///do stuff
    int i = delegate();
    return i!=0;
}

public static void Main(String[] args)
{
    var answer = MethodWithDelegate(()=> DoStuff("On This random string that the MethodWithDelegate doesn't know about."));
}
rtgher
  • 149
  • 7