如何从 Action()返回值?

关于这个问题 Passing DataContext into Action()的答案,我如何从 action (db)返回一个值?

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

应该更像是:

MyType myType = SimpleUsing.DoUsing<MyType>(db => {
// do whatever with db.  query buit using db returns MyType.
});
167442 次浏览

可以使用 Func<T, TResult>通用委托(参见 MSDN)

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

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

  • Converter<TInput, TOutput>(MSDN)
  • 始终返回 bool (MSDN)

方法:

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

一般代表:

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

执行:

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

或明确地:

MyType myTypeInstance = SimpleUsing.DoUsing(db => return new MyType());

您还可以利用这样一个事实,即 lambda 或匿名方法可以关闭其封闭范围内的变量。

MyType result;


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


//do something with result

你的静态方法应该是:

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

致:

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

这个答案源于注释,所以我可以提供代码。有关详细说明,请参阅下面@sll 的回答。

使用 Func<T>而不是 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.

如果希望为函数提供参数,请使用 Func<TParameter1, TParameter2, ..., TReturn>

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);