Question

How to Pass a Method as a Parameter in C# Using Delegates

csharp.netmethodsdelegates

Question

I have several methods with the same parameter types and return values, but they have different names and different implementations. I want to pass one of these methods into another method and have that method call it.

For example, I am trying to do something like this:

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

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

public bool RunTheMethod([method parameter goes 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 as written, but it shows what I am trying to achieve. What I do not understand is how to define the parameter type in RunTheMethod so that it can accept a method and invoke it.

Short Answer

By the end of this page, you will understand how C# allows methods to be passed as parameters using delegates. You will learn the modern Func<...> syntax, see how it matches method signatures, and understand how to call the passed method inside another method. You will also see practical examples, common mistakes, and how this pattern is used in real C# codebases.

Concept

In C#, you cannot pass a method by writing a parameter type like "method name". Instead, you pass a delegate.

A delegate is a type that represents a reference to a method with a specific signature.

A method signature includes:

  • the parameter types
  • the return type

If two methods have the same signature, they can both be assigned to the same delegate type.

For the example in this question, both methods match this signature:

  • input: string
  • output: int

That means RunTheMethod should accept something that represents "any method that takes a string and returns an int".

In modern C#, the most common way to do this is with Func<string, int>.

  • Func<string, int> means:
    • takes a string
    • returns an int

So instead of trying to pass a method name directly, you define the parameter like this:

public bool RunTheMethod(Func<string, int> myMethodName)

Then you can call it like a normal method:

int i = myMethodName("My String");

This matters in real programming because it lets you write reusable code. Instead of duplicating logic, you can write one method that performs shared setup or cleanup, while letting the caller decide which specific operation should run.

Mental Model

Think of a delegate like a remote control button.

The RunTheMethod function does not need to know the actual method's name in advance. It only needs a button it can press.

If the button is wired to Method1, pressing it runs Method1. If the button is wired to Method2, pressing it runs Method2.

What matters is that every button works the same way:

  • it accepts one string
  • it gives back one int

So RunTheMethod is not asking for a specific method name. It is asking for anything callable with that shape.

Take Quiz

Syntax and Examples

The simplest modern solution uses Func<TInput, TResult>.

using System;

public class Example
{
    public int Method1(string input)
    {
        return input.Length;
    }

    public int Method2(string input)
    {
        return input.IndexOf(' ');
    }

    public bool RunTheMethod(Func<string, int> myMethod)
    {
        int result = myMethod("My String");
        Console.WriteLine(result);
        return true;
    }

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

What this means

  • Func<string, int> defines a method type.
  • Method1 matches that type because it takes a string and returns an int.
  • RunTheMethod(Method1) passes the method itself.
  • Inside RunTheMethod, myMethod("My String") invokes the passed method.

Another example with two methods

using System;

public class Example
{
    public int Method1(string input)
    {
        return input.Length;
    }

    public int Method2(string input)
    {
        return input.ToUpper().GetHashCode();
    }

    public void RunTheMethod(Func<string, int> myMethod)
    {
        int result = myMethod("hello");
        Console.WriteLine($"Result: {result}");
    }

    public void Demo()
    {
        RunTheMethod(Method1);
        RunTheMethod(Method2);
    }
}

Both methods can be passed because both have the same signature.

Using a custom delegate

Before Func became common, developers often created named delegates.

public delegate int StringOperation(string input);

public bool RunTheMethod(StringOperation myMethod)
{
    int i = myMethod("My String");
    return true;
}

This still works and can be useful when you want a more descriptive type name.

Step by Step Execution

Consider this small example:

using System;

public class Example
{
    public int Method1(string input)
    {
        return input.Length;
    }

    public bool RunTheMethod(Func<string, int> myMethod)
    {
        int i = myMethod("My String");
        Console.WriteLine(i);
        return true;
    }

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

Step-by-step

  1. Test() is called.

  2. Test() calls RunTheMethod(Method1).

  3. The method Method1 is passed into RunTheMethod as a delegate.

  4. Inside RunTheMethod, the parameter myMethod now refers to Method1.

  5. This line runs:

    int i = myMethod("My String");
    
  6. Since myMethod refers to Method1, this is effectively the same as:

    int i = Method1("My String");
    
  7. Method1 receives the string "My String".

  8. It returns the length of that string.

  9. The result is stored in i.

  10. RunTheMethod prints the value and returns true.

  11. Test() returns true.

Key idea

The receiving method does not care which specific method was passed. It only cares that the method matches the expected signature.

Real World Use Cases

Passing methods as parameters is very common in C#.

1. Reusable processing pipelines

You may have a method that handles logging, timing, or validation, and then runs one of several operations.

public int ExecuteWithLogging(Func<string, int> operation, string input)
{
    Console.WriteLine("Starting...");
    int result = operation(input);
    Console.WriteLine("Done.");
    return result;
}

2. Sorting and filtering

LINQ uses this idea heavily. You pass logic into methods like Where, Select, and OrderBy.

var shortNames = names.Where(name => name.Length < 5);

The lambda is a function passed as a parameter.

3. Event handling

In UI apps and desktop apps, methods are passed as handlers for clicks, changes, or other events.

4. Retry and error-handling wrappers

You can pass an operation into a generic method that retries on failure.

5. Business rules

An application may pass different calculation methods depending on customer type, pricing mode, or feature flags.

Take Quiz

Real Codebase Usage

In real projects, this pattern is often used to separate shared workflow from custom behavior.

Common patterns

  • Guard clauses before invoking the method
  • Validation of input
  • Logging around execution
  • Error handling with try/catch
  • Configuration-based behavior where one of several methods is chosen dynamically

Example with a guard clause

public bool RunTheMethod(Func<string, int> myMethod)
{
    if (myMethod == null)
    {
        throw new ArgumentNullException(nameof(myMethod));
    }

    int result = myMethod("My String");
    Console.WriteLine(result);
    return true;
}

Example with shared workflow

public int RunWithAudit(Func<string, int> operation, string input)
{
    Console.WriteLine($"Running operation with input: {input}");

    int result = operation(input);

    Console.WriteLine($"Operation returned: {result}");
    return result;
}

This lets the codebase avoid repeating the audit logic in every individual method.

Choosing behavior dynamically

Func<string, int> operation = useMethod1 ? Method1 : Method2;
int result = operation("sample");

This is useful when behavior depends on runtime conditions.

Common Mistakes

1. Passing the result instead of the method

Broken code:

RunTheMethod(Method1("Hello"));

Why it is wrong:

  • Method1("Hello") executes immediately.
  • It returns an int.
  • But RunTheMethod expects a delegate, not an int.

Correct:

RunTheMethod(Method1);

2. Using the wrong delegate type

Broken code:

public bool RunTheMethod(Action<string> myMethod)

Why it is wrong:

  • Action<string> means the method takes a string and returns void.
  • Your methods return int, so this does not match.

Correct:

public bool RunTheMethod(Func<string, int> myMethod)

3. Signature mismatch

Broken code:

public int Method3(int x)
{
    return x;
}

RunTheMethod(Method3);

Why it is wrong:

  • Method3 takes an int, not a string.
  • Delegate signatures must match.

4. Forgetting null checks

Broken code:

public bool RunTheMethod(Func<string, int> myMethod)
{
    int i = myMethod("My String");
    return true;
}

If myMethod is null, this throws an exception.

Safer version:

public bool RunTheMethod(Func<string, int> myMethod)
{
    if (myMethod == null)
        throw new ArgumentNullException(nameof(myMethod));

    int i = myMethod("My String");
    return true;
}

5. Confusing instance methods and static methods

If Method1 is an instance method, you need an object instance to pass it from outside the class.

var example = new Example();
example.RunTheMethod(example.Method1);

Comparisons

ApproachWhat it isBest forExample
Func<string, int>Built-in generic delegateMost common casesRunTheMethod(Func<string, int> method)
Custom delegateNamed delegate typeWhen you want clearer domain meaningdelegate int StringOperation(string input);
Lambda expressionInline functionShort one-off behaviorRunTheMethod(s => s.Length)
Action<string>Delegate with no return valueMethods that return voidAction<string>

Func vs Action

TypeTakes parametersReturns value
Func<T, TResult>YesYes
Action<T>YesNo

Method group vs lambda

RunTheMethod(Method1);
RunTheMethod(s => s.Length);

Both are valid.

  • Method1 passes an existing method.
  • s => s.Length creates inline logic.

Custom delegate vs Func

Use Func when:

  • the signature is simple
  • you want less boilerplate

Use a custom delegate when:

  • the method type has an important meaning in your domain
  • the delegate name makes code easier to read
Take Quiz

Cheat Sheet

// Method signature to match
int SomeMethod(string input)
// Receive a method as a parameter
public bool RunTheMethod(Func<string, int> myMethod)
{
    int result = myMethod("My String");
    return true;
}
// Pass a method
RunTheMethod(Method1);
// Pass a lambda instead
RunTheMethod(s => s.Length);
// Custom delegate alternative
public delegate int StringOperation(string input);

Rules

  • The method signature must match exactly.
  • Use Func<...> for methods that return a value.
  • Use Action<...> for methods that return void.
  • Do not call the method when passing it unless you want the result instead of the method.
  • Check for null before invoking a delegate if needed.

Common signatures

  • Func<int> → returns int, takes no parameters
  • Func<string, int> → takes string, returns int
  • Action → takes no parameters, returns void
  • Action<string> → takes string, returns void

FAQ

How do you pass a method as a parameter in C#?

Use a delegate type such as Func or Action. For a method that takes a string and returns an int, use Func<string, int>.

What is a delegate in C#?

A delegate is a type that can store a reference to a method with a specific signature.

When should I use Func instead of Action?

Use Func when the method returns a value. Use Action when the method returns void.

Can I pass a lambda instead of a named method?

Yes. For example:

RunTheMethod(s => s.Length);

Does the method signature need to match exactly?

Yes. The parameter types and return type must match the delegate type.

Can instance methods be passed as parameters?

Yes, as long as you pass them from an object instance when needed.

Is Func better than creating a custom delegate?

Usually yes for simple cases. A custom delegate is useful when a named delegate makes the code clearer.

Take Quiz

Mini Project

Description

Build a small text-processing utility where one method handles the common workflow and accepts different string-processing methods as parameters. This demonstrates how delegates let you reuse one execution pipeline while changing the behavior that runs inside it.

Goal

Create a program that can run different string-to-int operations through a shared method.

Requirements

  1. Create at least two methods that take a string and return an int.
  2. Write a RunOperation method that accepts one of those methods as a parameter.
  3. Call RunOperation with each method.
  4. Print the result of each operation.
  5. Add a null check before invoking the passed method.
Take Quiz

Keep learning

Related questions

View more