121

In regards to the answer for this question Passing DataContext into Action(), how do I return a value from action(db)?

SimpleUsing.DoUsing(db => { 
// do whatever with db 
}); 

Should be more like:

MyType myType = SimpleUsing.DoUsing<MyType>(db => { 
// do whatever with db.  query buit using db returns MyType.
}); 
Community
  • 1
  • 1
4thSpace
  • 43,672
  • 97
  • 296
  • 475

5 Answers5

137

You can use Func<T, TResult> generic delegate. (See MSDN)

Func<MyType, ReturnType> func = (db) => { return new MyType(); }

Also there are useful generic delegates which considers a return value:

  • Converter<TInput, TOutput> (MSDN)
  • Predicate<TInput> - always return bool (MSDN)

Method:

public MyType SimpleUsing.DoUsing<MyType>(Func<TInput, MyType> myTypeFactory)

Generic delegate:

Func<InputArgumentType, MyType> createInstance = db => return new MyType();

Execute:

MyType myTypeInstance = SimpleUsing.DoUsing(
                            createInstance(new InputArgumentType()));

OR explicitly:

MyType myTypeInstance = SimpleUsing.DoUsing(db => return new MyType());
Riggeot
  • 89
  • 2
  • 8
sll
  • 61,540
  • 22
  • 104
  • 156
  • Right - can you provide an example of what the method should look like? – 4thSpace Nov 11 '11 at 20:38
  • I sitll don't follow how this fits in. Can you show it with the method signature (i.e. public static void DoUsing(Action action))? @L.B: yes - my post is the result. – 4thSpace Nov 11 '11 at 20:45
  • 9
    @L.B -- asking people to google is not constructive. SO exists to provide complete answers. – Kirk Woll Nov 11 '11 at 20:46
  • @4thSpace, the problem is that `SimpleUsing.DoUsing` is written to consume an `Action` -- it needs to be overloaded to *also* support `Func`. – Kirk Woll Nov 11 '11 at 20:47
  • 5
    @KirkWoll But the answer gives the **ingredients**, it doesn't have be **cooked** – L.B Nov 11 '11 at 20:48
  • 13
    @L.B. -- it's better for it to be complete. I find your analogy spurious. – Kirk Woll Nov 11 '11 at 20:49
  • @Kirk, it doesn't need to consume Action. That's just what I started with. The answer from the previous solution is what I need. But now I need it to return a Type I provide, however that solution should look. That's where I'm at now. – 4thSpace Nov 11 '11 at 20:49
  • 3
    @L.B, better to not comment since you aren't adding any value what so ever. – 4thSpace Nov 11 '11 at 20:51
  • This did not answer the question. He is looking for how to return a value from an action delegate, not func delegate... – Shane Sepac Jan 29 '17 at 05:34
  • 1
    @Shn_Android_Dev - you're right but Action is not a facility to return a value, surely we can turn around and reinvent the wheel but does such code complication worth sticking principally to Action? – sll Feb 02 '17 at 00:21
117

Your static method should go from:

public static class SimpleUsing
{
    public static void DoUsing(Action<MyDataContext> action)
    {
        using (MyDataContext db = new MyDataContext())
           action(db);
    }
}

To:

public static class SimpleUsing
{
    public static TResult DoUsing<TResult>(Func<MyDataContext, TResult> action)
    {
        using (MyDataContext db = new MyDataContext())
           return action(db);
    }
}

This answer grew out of comments so I could provide code. For a complete elaboration, please see @sll's answer below.

Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
24

Use Func<T> rather than Action<T>.

Action<T> acts like a void method with parameter of type T, while Func<T> works like a function with no parameters and which returns an object of type T.

If you wish to give parameters to your function, use Func<TParameter1, TParameter2, ..., TReturn>.

Ulysses Alves
  • 2,297
  • 3
  • 24
  • 34
15

You can also take advantage of the fact that a lambda or anonymous method can close over variables in its enclosing scope.

MyType result;

SimpleUsing.DoUsing(db => 
{
  result = db.SomeQuery(); //whatever returns the MyType result
}); 

//do something with result
Steve Rowbotham
  • 2,868
  • 17
  • 18
  • yeah, this is called Closure (funcitonal language stuff which is available for us as well) – sll Nov 11 '11 at 21:08
1

In addition to ssls answer: For a software we call a lot of "micro methods" to query this and that from the local machine. Sometimes exceptions appear (file / folder not existing, etc). In order to not repeat our self over and over with try/catch blocks, we used ssls approach with return values:

private T ExecuteAndCatch<T>(Func<T> action, T defaultReturn)
{
    try
    {
        return action();
    }
    catch (Exception ex)
    {
        Log.e("Exception during ExecuteAndCatch", ex);
        return defaultReturn;
    }
}

Example of mentioned micro-methods:

private Boolean CheckKasperskyInstalled() => System.IO.File.Exists(Environment.ExpandEnvironmentVariables(@"%pf_x86%\Kaspersky Lab\Kaspersky Endpoint Security for Windows\avp.exe"));
private Boolean CheckKasperskyRunning() => System.Diagnostics.Process.GetProcessesByName("avp").Length > 0;

And when using, we no longer have to care if these Methods might throw an exception for whatever reason:

cci = new ComputerComplianceInfo();
cci.KasperskyInstalled = ExecuteAndCatch(() => CheckKasperskyInstalled(), false);
cci.KasperskyRunning = ExecuteAndCatch(() => CheckKasperskyRunning(), false);
dognose
  • 20,360
  • 9
  • 61
  • 107