【问题标题】:How to return value from Action()?如何从 Action() 中返回值?
【发布时间】:2011-11-11 20:35:34
【问题描述】:

关于这个问题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.
}); 

【问题讨论】:

    标签: c# .net linq


    【解决方案1】:

    您可以使用Func&lt;T, TResult&gt; 通用委托。 (见MSDN

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

    还有一些有用的考虑返回值的通用委托:

    • Converter&lt;TInput, TOutput&gt; (MSDN)
    • Predicate&lt;TInput&gt; - 总是返回 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());
    

    【讨论】:

    • @L.B -- 让人们使用谷歌搜索是没有建设性的。 SO 的存在是为了提供完整的答案。
    • @KirkWoll 但是答案给出了成分,它没有被煮熟
    • @L.B. ——最好是完整的。我发现你的类比是虚假的。
    • @L.B,最好不要发表评论,因为你从来没有增加任何价值。
    • @Shn_Android_Dev - 你是对的,但 Action 不是返回值的工具,我们当然可以转身重新发明轮子,但这种代码复杂性是否值得主要坚持使用 Action?
    【解决方案2】:

    你的静态方法应该来自:

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

    这个答案来自 cmets,所以我可以提供代码。有关完整的详细说明,请参阅下面的@sll 答案。

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 是的,这叫做闭包(我们也可以使用功能语言的东西)
      【解决方案4】:

      使用Func&lt;T&gt; 而不是Action&lt;T&gt;

      Action&lt;T&gt; 的作用类似于具有 T 类型参数的 void 方法,而 Func&lt;T&gt; 类似于没有参数并返回 T 类型对象的函数。

      如果您想为函数提供参数,请使用Func&lt;TParameter1, TParameter2, ..., TReturn&gt;

      【讨论】:

        【解决方案5】:

        除了 ssls 答案:对于一个软件,我们调用了很多“微方法”来从本地机器查询这个和那个。有时会出现异常(文件/文件夹不存在等)。为了不重复使用 try/catch 块,我们使用了带有返回值的 ssls 方法:

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

        提到的微方法示例:

        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;
        

        并且在使用时,我们不再需要关心这些方法是否会因任何原因抛出异常:

        cci = new ComputerComplianceInfo();
        cci.KasperskyInstalled = ExecuteAndCatch(() => CheckKasperskyInstalled(), false);
        cci.KasperskyRunning = ExecuteAndCatch(() => CheckKasperskyRunning(), false);
        

        【讨论】:

          【解决方案6】:

          我也有这个需求,但涉及跨线程问题 - MainForm 中的方法从 UserControl 中的控件返回数据。 Original code was an extension method that perform an Action;后来,我需要返回一个值,正如@sll 建议的那样,我不得不改用 Func 委托。

          在 ControlExtensions 类中:

               public static TResult RunOnUiThread<TResult>(this Control @this, Func<TResult> code)
                  {
                      if (@this.InvokeRequired)
                      {
                          var toReturn = @this.BeginInvoke(code);                  
                          return (TResult)@this.EndInvoke(toReturn);
                      }
                      else
                      {
                          return code.Invoke();
                      }
                 }
          

          这个扩展方法是从 MainForm 中的一个方法调用的,从 UserControl 内部的一个控件中获取一些值;在此示例中,我从 ListBox 返回 SelectedItem 的值:

                          return UserControl1.listBox1.RunOnUiThread(
                              () => UserControl1.listBox1.GetItemText(
                                      UserControl1.listBox1.SelectedItem)
                              );
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-04-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-12-22
            • 2017-12-20
            相关资源
            最近更新 更多