【问题标题】:Method Call using Ternary Operator使用三元运算符的方法调用
【发布时间】:2021-08-20 08:52:34
【问题描述】:

在尝试新概念时,我发现了Ternary Operator 及其美丽之处。玩了一段时间后,我决定测试一下它的极限。

但是,当我无法编译某行代码时,我的乐趣很快就结束了。

int a = 5;
int b = 10;
a == b ? doThis() : doThat() 

    private void doThis()
    {
        MessageBox.Show("Did this");
    }
    private void doThat()
    {
        MessageBox.Show("Did that");
    }

这一行给了我两个错误:

Error   1   Only assignment, call, increment, decrement, and new object expressions can be used as a statement
Error   2   Type of conditional expression cannot be determined because there is no implicit conversion between 'void' and 'void'

我从来没有使用过Ternary Operator 来决定调用哪个方法,我也不知道它是否可行。我只是喜欢使用单行 If Else Statement 进行方法调用的想法。

我做了一些研究,但找不到任何人这样做的例子,所以我想我可能希望有一些不可能的事情。

如果可以的话,请指教我的错误做法,不可以,有没有别的办法?

【问题讨论】:

  • 确保函数 doThis 和 doThat 返回一个 int 类型的值。
  • 如果你真的想要一行If Else,就写成一行:if (condition) doThis(); else doThat();并不总是一件好事。

标签: c# conditional-operator


【解决方案1】:

三元运算符用于返回值,这些值必须被赋值。假设 doThis()doThat() 方法返回值,一个简单的赋值就可以解决你的问题。

如果你想做你正在尝试的事情,这是可能的,但解决方案并不漂亮。

int a = 5;
int b = 10;
(a == b ? (Action)doThis : doThat)();

这将返回一个 Action 委托,然后由括号调用该委托。这不是实现这一目标的典型方式。

【讨论】:

  • 确实,这不是正确的做事方式;但绝对是该问题的最正确答案:OP 想要使用三元运算符来选择要调用的方法,而这正是您的 sn-p 所做的;)
  • 为什么这不“正确”?另一张海报甚至称其为愚蠢。
  • 这对新的表达式主体运算符 (=>) 非常有用
【解决方案2】:

方法一:使用动作

Action Action = true is true ? new Action(() => A()) : new Action(() => B());
Action.Invoke();

方法二:使用扩展

Button Button = new Button(){
    IsEnabled = false
};
Button.Switch((x) => x.IsEnabled).Invoke(() => A(), () => B())

扩展开关:

public static R Switch<T, R>(this T sender, Func<T, R> method){
    return method.Invoke(sender);
}

扩展调用:

public static void Invoke(this bool condition, Action @true, Action @false){
    Action Action = condition ? @true : @false;
    Action.Invoke();
}

方法 3:使用扩展和 C# 6.0 空条件运算符

Button.Case((x) => 0 > 1)?.With(() => A());
Button.Case((x) => 0 < 1)?.With(() => B());

扩展名:

public static T With<T>(this T sender, Action method){
    method.Invoke();
    return sender;
}

扩展案例:

public static object Case<T>(this T sender, Func<T, bool> method){
    return method.Invoke(sender) ? Convert.ChangeType(sender, typeof(T)) : null;
}

【讨论】:

    【解决方案3】:

    不过,您应该能够做到这一点:

            int a = 5;
            int b = 10;
    
            var func = a == b ? (Action)doThis : (Action)doThat; // decide which method
    
            func(); // call it
    

    虽然它并不是真的那么有用。

    【讨论】:

    • 在每个函数之前有(Action) 对我来说更有意义,但其他人的例子在doThis 之前有它。两者都正确吗?
    【解决方案4】:

    如果你真的想在条件运算符中调用void 方法,你可以使用委托:

    (something ? new Action(DoThis) : DoThat)();
    

    如果方法带参数,这将变得更加复杂。
    您可以将 lambda 表达式放在条件中,也可以使用 Action&lt;T&gt;

    但是,这是一件非常愚蠢的事情。

    【讨论】:

      【解决方案5】:

      上述说法不起作用的原因是其他用户提供的,实际上并没有回答我的真实问题。

      玩了一会儿,我发现你可以使用这个操作符来做上面的语句,但是它会导致一些错误的代码。

      如果我把上面的语句改成;

      int a = 5;
      int b = 10;
      int result = a == b ? doThis() : doThat(); 
      
      private int doThis()
      {
          MessageBox.Show("Did this");
          return 0;
      }
      private int doThat()
      {
          MessageBox.Show("Did that");
          return 1;
      }
      

      此代码将按应有的方式编译和执行。但是,如果这些方法最初不打算返回任何内容,并且在代码中引用了其他区域,那么您现在必须每次都处理一个返回对象才能调用这些方法。

      否则,您现在可以将三元运算符用于单行方法选择器,甚至可以使用结果知道它在下一行中调用了哪个方法。

      int result = a == b ? doThis() : doThat();
      
      if (result == 0)
         MessageBox.Show("You called doThis()!");
      

      现在,这段代码完全没有意义,可以通过 If Else 轻松完成,但我只是想知道它是否可以完成,以及你必须做什么才能让它工作。

      现在我知道您可以在这些方法中有效地返回任何类型,这可能会变得更有用一些。它可能被认为是一种“糟糕的编码实践”,但在它从来不适合的情况下可能会变得非常有用。

      您可以根据任何条件访问一个或另一个对象,这在一行代码中可能非常有用。

      UserPrivileges result = user.Group == Group.Admin ? GiveAdminPrivileges() : GiveUserPrivileges();
      
      private UserPrivileges GiveAdminPrivileges()
      {
            //Enter code here
            return var;
      }
      private UserPrivileges GiveUserPrivileges()
      {
            //Enter code here
            return var;
      }
      

      当然,这可以通过 If 语句来完成,但我认为将三元运算符用于其他用途会使编程变得有趣。现在,这可能不如 If Else 语句那么有效,在这种情况下,我永远不会使用它。

      【讨论】:

      • 同意,但为了完整起见,您还可以返回一个布尔值、字符串或任何对象。但实际上,声明 1;对编译器真的意味着什么?不多,而且它无助于学习良好编码实践的细微差别
      • @Michael 我不知道,这就是我的问题的重点。我想知道如何让它发挥作用以及使用它的好处/后果。选择返回类型的能力使它更加有用。
      【解决方案6】:

      .NET 不(容易)支持(可读版本)这个是有原因的。它非常笨拙,使您的代码难以阅读。逻辑树应该相对容易遍历。如果我走进一份工作,他们使用三元组分配值、调用方法等的所有代码。我想我会直接离开。

      【讨论】:

      • 你还需要一个作业。
      • 我认为这会使代码难以阅读的唯一方法是使用非描述性变量名称和幻数(似乎没有意义的数字)。如果正确使用三元运算符,它应该像 If/Else 一样简单。
      • 方法名称可能很长并且经常涉及参数。我不想阅读 200 个字符的行来确定一个方法调用从哪里开始,另一个在哪里结束。多行(至少对我而言)通常更容易阅读,并且几乎从不需要多行。比较:(VicePresidentsAttendee.AnnualSalary == MoneyHelper.MonetizeInt(SalaryThreshold)) ? RaiseHelper.AddABillionDollarBonus(VicePresidentAttendee.PersonId) : RaiseHelper.RegisterPersonForYearlyRaise(SalaryThreshold, PersonId, SickDaysLastQuarter, TypingSpeedInGoalWordsPerMinute, LunarPhaseOnLastPiDay);
      • 乱码?你杀死了谷歌翻译:-)(还有必应)
      【解决方案7】:

      条件运算符是一个返回值的表达式。
      您不能将它与返回 void 的函数一起使用。

      您应该使用普通的if

      【讨论】:

      • 但是,也许 OP 假设用户可以在 C/C++ 样式语法中使用条件运算符,其中语法将允许用户在条件操作中调用方法。但我假设从 OP 所说的来看,他们并没有将条件运算符的使用基于 C/C++ 语法。
      【解决方案8】:

      三元运算符必须返回一些东西。一个典型的用法是这样的:

      int x = (a > b) ? a : b;
      

      如果你尝试类似的东西

      a + b;
      

      编译器会抱怨。

      (a > b) ? a - b : b - a;
      

      基本上是“a - b”或“b - a”的捷径,它们本身不是合法的陈述。

      【讨论】:

      • +1。如果 DoThis() 和 DoThat() 返回了一些东西,你可以使用三元来控制执行并将结果分配给一些局部变量,但这不是三元运算符的意图;其他开发人员会认为返回值对您来说比副作用更重要。使用基本的 if 语句;你的意图将保持清晰(你不必为了聪明而弄乱你的方法签名)。
      • +1,另一个关键点是可以从三元运算符返回的两个值必须是相同类型或隐式转换为相同类型。
      猜你喜欢
      • 1970-01-01
      • 2019-03-29
      • 2013-06-29
      • 1970-01-01
      • 2011-10-05
      • 2013-08-27
      • 2020-03-14
      相关资源
      最近更新 更多