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
- takes a
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.
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.Method1matches that type because it takes astringand returns anint.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
-
Test()is called. -
Test()callsRunTheMethod(Method1). -
The method
Method1is passed intoRunTheMethodas a delegate. -
Inside
RunTheMethod, the parametermyMethodnow refers toMethod1. -
This line runs:
int i = myMethod("My String"); -
Since
myMethodrefers toMethod1, this is effectively the same as:int i = Method1("My String"); -
Method1receives the string"My String". -
It returns the length of that string.
-
The result is stored in
i. -
RunTheMethodprints the value and returnstrue. -
Test()returnstrue.
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.
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
RunTheMethodexpects a delegate, not anint.
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 astringand returnsvoid.- 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:
Method3takes anint, not astring.- 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
| Approach | What it is | Best for | Example |
|---|---|---|---|
Func<string, int> | Built-in generic delegate | Most common cases | RunTheMethod(Func<string, int> method) |
| Custom delegate | Named delegate type | When you want clearer domain meaning | delegate int StringOperation(string input); |
| Lambda expression | Inline function | Short one-off behavior | RunTheMethod(s => s.Length) |
Action<string> | Delegate with no return value | Methods that return void | Action<string> |
Func vs Action
| Type | Takes parameters | Returns value |
|---|---|---|
Func<T, TResult> | Yes | Yes |
Action<T> | Yes | No |
Method group vs lambda
RunTheMethod(Method1);
RunTheMethod(s => s.Length);
Both are valid.
Method1passes an existing method.s => s.Lengthcreates 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
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 returnvoid. - Do not call the method when passing it unless you want the result instead of the method.
- Check for
nullbefore invoking a delegate if needed.
Common signatures
Func<int>→ returnsint, takes no parametersFunc<string, int>→ takesstring, returnsintAction→ takes no parameters, returnsvoidAction<string>→ takesstring, returnsvoid
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.
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
- Create at least two methods that take a
stringand return anint. - Write a
RunOperationmethod that accepts one of those methods as a parameter. - Call
RunOperationwith each method. - Print the result of each operation.
- Add a null check before invoking the passed method.
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
Best Way to Repeat a Character in C#: Building Repeated Strings Efficiently
Learn the best way to repeat a character in C#, compare StringBuilder, string concatenation, and simpler built-in options.
C# Access Modifiers and static: public, private, protected, and Defaults
Learn how C# public, private, protected, and default access control visibility, and how static differs from instance members.