13

I have a parametric method that takes a Func as an argument

SomeType SomeMethod<T>( Func<T, T> f ) {...}

I would like to pass an Action without having to overload the method. But this takes to the problem, how do you represent and Action as a Func? I tried

Func<void, void>

but its not valid.

Dan S
  • 9,139
  • 3
  • 37
  • 48
Cristian Garcia
  • 9,630
  • 6
  • 54
  • 75
  • 10
    you **can't**....... – Selman Genç May 30 '14 at 17:43
  • 8
    And never will be, Func does not allow void return types (because of that the existance of Action delegate). You can always wrap your Action into a lambda (o) => { ExecuteAction(); return true; } – Gusman May 30 '14 at 17:43
  • Very good question, and also one that does not have a satisfactory answer in C#. You are running into this issue: http://james-iry.blogspot.com/2009/07/void-vs-unit.html – isekaijin May 30 '14 at 17:46
  • @Gusman yeah, It's basically what I am doing, but that makes me write an unnecessary return, which is what I am trying to solve. – Cristian Garcia May 30 '14 at 17:47
  • 1
    If the return isn't necessary why does SomeMethod expect a Func? Surely it's using that return value. – Kyle May 30 '14 at 18:19

3 Answers3

12

You can create an extension method to wrap an action and return a dummy value:

public static class ActionExtensions
{
    public static Func<T, T> ToFunc<T>(this Action<T> act)
    {
        return a => { act(a); return default(T) /*or a*/; };
    }
}

Action<?> act = ...;
SomeMethod(act.ToFunc());

It might be clearer if you create your own Unit type instead of using object and returning null.

Lee
  • 142,018
  • 20
  • 234
  • 287
  • Never used default, what does it do? – Cristian Garcia May 30 '14 at 17:55
  • 1
    @CristianGarcia - It returns `null` for reference types and 'zero' for value types. – Lee May 30 '14 at 17:57
  • I get this error: `Extension method must be defined in a non-generic static class` – Cristian Garcia May 30 '14 at 18:27
  • @CristianGarcia - You have to define extension methods in static classes - see update. – Lee May 30 '14 at 18:41
  • @CristianGarcia Also, structs are value types that can't be set to 0. The default value of a struct is where all its value properties are set to 0 and its reference properties are set to null. http://msdn.microsoft.com/en-us/library/aa664475(v=vs.71).aspx – Mister Epic Jun 02 '14 at 10:40
3

.NET Fiddle

What you are looking for is a "statement lambda" msdn.

A statement lambda is when you wrap your expression (right hand side) in curly braces {}. This allows for more than 1 statement to be used. For your specific example, you could do this:

void Main()
{
    Func<bool,bool> f = i => {SomeAction();return true;};
    Console.WriteLine(SomeMethod(f));
}

public T SomeMethod<T>( Func<T, T> f ) 
{
    return f(default(T));
}

public void SomeAction()
{
    Console.WriteLine("called");
}

output

called
True
Travis J
  • 81,153
  • 41
  • 202
  • 273
1

You can't turn an Action into a Func. But you could wrap a call to the Action in a Func. For example, something like:

Action a = new Action<Foo>(f => { whatever });

Foo myFoo = ...;
Foo result = SomeMethod(new Func<Foo, Foo>(f => { a(myFoo); return myFoo; }));

(Don't have Visual Studio up at the moment, but I think you get the idea.)

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351