How to return value from Action?
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
In C#, Action is a delegate type that represents a method returning void — it performs work but does not return a value. If you need a delegate that returns a value, use Func<TResult> instead. However, there are legitimate scenarios where you have an existing Action-based API and need to extract a result. The workarounds include using Func<T> (the correct solution), out parameters, captured variables (closures), or wrapping the Action in a Task.
Action vs Func — The Core Difference
If you need a return value, Func<TResult> is the correct delegate type.
Solution 1: Use Func<T> Instead of Action (Recommended)
If you control the API, change Action parameters to Func<T>:
Solution 2: Captured Variable (Closure)
When you cannot change the delegate type (e.g., third-party API), capture a variable in the closure.
Solution 3: out Parameter via Wrapper
Solution 4: Convert Action to Func with a Wrapper
Solution 5: Using Task for Async Scenarios
When Each Approach Is Appropriate
| Scenario | Approach |
| You control the API | Change Action to Func<T> |
| Third-party callback API | Captured variable (closure) |
| Need thread-safe result passing | TaskCompletionSource<T> |
| Simple one-off extraction | out parameter wrapper |
| Adapting Action for Func-expecting API | Wrapper function |
Common Pitfalls
- Using
ActionwhenFuncis what you need: If you are designing an API and the operation produces a result, useFunc<TResult>from the start. Trying to extract return values fromActionis a workaround, not a pattern. - Thread safety with captured variables: When using closures to capture results across threads, the captured variable is not thread-safe. The
Actionmay complete on a different thread, and reading the variable without synchronization causes race conditions. UseTaskCompletionSource<T>orInterlockedfor cross-thread result passing. - Calling
.Resulton tasks inside Action: Using.Resultor.Wait()on async operations inside anActioncan deadlock, especially in UI or ASP.NET contexts with a synchronization context. Useasync/awaitwithFunc<Task<T>>instead. - Confusing
Action<T>withFunc<T>:Action<T>takes a parameter of typeTand returns void.Func<T>takes no parameters and returnsT.Func<T, TResult>takesTand returnsTResult. Mixing these up causes compile errors that may be confusing. - Over-engineering with wrappers when refactoring is possible: If you can change the delegate type, just change it. Adding wrapper classes, captured variables, and adapter patterns around
Actionto simulate return values adds unnecessary complexity. Refactor toFunc<T>when feasible.
Summary
Actionreturnsvoid— useFunc<TResult>when you need a return value- If you cannot change the delegate type, use a captured variable (closure) to extract the result
- Use
TaskCompletionSource<T>for async scenarios with callback-based APIs Func<T>is the idiomatic C# approach — prefer it over workarounds- Avoid
.Resultand.Wait()insideActiondelegates to prevent deadlocks
Related reading
- How to return value with anonymous method?
- How to run Command Prompt commands from C
- How to select all text in Winforms NumericUpDown upon tab in?
- How to select different app.config for several build configurations
- How to select .NET 4.5.2 as a target framework in Visual Studio
- How to select only the records with the highest date in LINQ
- How to send an email in .Net according to new security policies?
- How to send an HTTPS GET Request in C

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.