Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

How do I make a generic wrapper method that returns the wrapped method's result, if it has one?

Ask Question

I'm trying to make a method that accepts another method, and returns the value that the inner method returns, if that inner method isn't void. I'd like to do it without differentiating between Func<> and Action<> .

Essentially, I want the wrapped method to behave the exact same way as the unwrapped method, plus some functionality provided by the wrapper. The goal is simple enough, but it's hard to wrap my head around the implementation.

public int ReturnsInteger() {
    Console.WriteLine("I return 42");
    return 42;
public static T WrapperMethod(Func<T> someMethod) {
    Console.WriteLine("Wrap start");
    var result = someMethod();
    Console.WriteLine("Wrap end");
    return result;
private static void Main() {
    var X = WrapperMethod(()=>ReturnsInt());
    Console.WriteLine("X = " + X);
    // Wrap start
    // I return 42
    // Wrap end
    // X = 42
public void ReturnsNothing() {
    Console.WriteLine("I return nothing");
    return;
public static T WrapperMethod(Action someMethod) {
    Console.WriteLine("Wrap start");
    someMethod();
    Console.WriteLine("Wrap end");
private static void Main() {
    WrapperMethod(()=>ReturnsNothing());
    // Wrap start
    // I return nothing
    // Wrap end
                You're going to need to have overloads for both Action and Func, but you could implement a Unit type to be returned by the wrapper for Actions.
– Jonathon Chase
                Jul 10, 2019 at 22:01
                Any solution you come up with is going to be radically more complex, and perform radically worse, than what you have here.  Trying to generalize this is in no way going to simplify this.  Just support the two different delegates.
– Servy
                Jul 10, 2019 at 22:14
                "I'm trying to make a method that accepts another method, and returns the value that the inner method returns, if that inner method isn't void" -- I don't even know what that means. That is, if the inner method has a return type of void, then you don't want your method that returns a value? C# doesn't work that way. Methods always either return a value or they don't...you can't make them conditionally return a value depending on the arguments.
– Peter Duniho
                Jul 10, 2019 at 23:00
                You've only got half your requirements here. For them to be complete, you'll have to specify what you expect your wrapper method to do if the inner method does indeed return void.
– John Wu
                Jul 10, 2019 at 23:18
                You all raise good points.  I was struggling for close to an hour trying to figure out how to ask the right question, but @PeterDuniho's answer captured the gist of the problem.
– TheGreatB3
                Jul 11, 2019 at 0:35

As noted above, I don't entirely understand the wording of your question. However, the basic scenario seems plain: you want to generically decorate the behavior of unknown methods, handling both methods that return values and those which don't.

Whenever I run into that type of scenario, I address it by writing one wrapper method that has return type void, and then adapting via a lambda a second wrapper method. For example:

T Wrapper<T>(Func<T> func)
    T result = default(T);
    Wrapper(() => { result = func(); });
    return result;
void Wrapper(Action action)
    Console.WriteLine("Wrap start");
    action();
    Console.WriteLine("Wrap end");

This way I only have to write the wrapper logic once. There's some overhead with the Func<T> version having to create a new delegate instance and capture a local variable, but at least when I've had to do this sort of thing, the wrapper logic and wrapped logic is complex enough that the overhead of the lambda is inconsequential.

Thanks for your answer. It seems odd to me that C# has to handle void methods separately from others, but this seems elegant enough. – TheGreatB3 Jul 11, 2019 at 0:27 For better or worse, C# follows the conventions set by C and similar languages, all of which treat a method with a return type different from one without. I suppose the C# designers could have deviated from that norm, which I suspect is based on the underlying architecture (for the x86-based processors, there's a distinction between returning a value or not), but that could've caused more consternation from programmers trying to move from other languages. Indeed, I'm not aware of any mainstream, statically-typed language that doesn't carry this distinction. – Peter Duniho Jul 11, 2019 at 0:31 @PeterDuniho Interestingly, there are a few actual uses. See stackoverflow.com/questions/5450748/what-is-system-void. I confess to never needing them though! – Kit Jul 11, 2019 at 2:01

I would try to take away the fundamental language difference of a void returning method by actually giving the method something to return.

By implementing a Unit type, that is just a single value struct, then you can transform Action into Func<Unit>. This is effectively just using the adapter pattern.

Now you're just dealing with one kind of delegate in the form of Func<T>. You can then put all of the hard work into that single Wrapper method.

Try this:

void Main()
    var result = Wrapper(DoSomething);
private void DoSomething()
    Console.WriteLine("Test.");
T Wrapper<T>(Func<T> func)
    Console.WriteLine("Wrap start");
    var result = func();
    Console.WriteLine("Wrap end");
    return result;
Unit Wrapper(Action action)
    return Wrapper(() => { action(); return Unit.Default; });
/// <summary>
/// Represents a type with a single value. This type is often used to denote the successful completion of a void-returning method (C#) or a Sub procedure (Visual Basic).
/// </summary>
[Serializable]
[StructLayout(LayoutKind.Sequential, Size = 1)]
public struct Unit : IEquatable<Unit>
    public static Unit Default => default(Unit);
    public bool Equals(Unit other) => true;
    public override bool Equals(object obj) => obj is Unit;
    public override int GetHashCode() => 0;
    public override string ToString() => "()";
    public static bool operator ==(Unit first, Unit second) => true;
    public static bool operator !=(Unit first, Unit second) => false;
                It would help if you would explain in your answer why you see this as a preferable approach vs other similar alternatives, e.g. defining void Wrapper(Action action) => Wrapper(() => { action(); return (object)null; });. Also, I'll note that type inference should take care your call to Wrapper<Unit>(): return Wrapper(() => { action(); return Unit.Default; });
– Peter Duniho
                Jul 11, 2019 at 1:32
                I like the improvement, but I'd still like to know how you see writing a whole new type as somehow better than just using object to call the Func<T> version of the wrapper.
– Peter Duniho
                Jul 11, 2019 at 2:09
                I for one think it's fascinating.  Before this I had never heard of unit types, but I'm interested in trying it out.  Can the same unit type be used anywhere (as in, I don't need to tweak it for my own implementations)?
– TheGreatB3
                Jul 11, 2019 at 3:21
                @TheGreatB3 - Yes, you can use it anywhere. It's just a value-type that can only ever be a single value. All voids just the same.
– Enigmativity
                Jul 11, 2019 at 5:59
                @PeterDuniho - Let me think about how best to express it. it's really just using the concept from functional programming, but that's a bit of a trite answer. I'll come back with something.
– Enigmativity
                Jul 11, 2019 at 6:00
        

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.