【问题标题】:Conditional operator and Comparison Delegate条件运算符和比较委托
【发布时间】:2012-03-18 07:17:03
【问题描述】:

给出两种比较方法的实现:

// compares by Key...
private static int CompareByKey(KeyValuePair<int, string> x, KeyValuePair<int, string> y)

{
    return x.Key.CompareTo(y.Key);
}

// compares by Value...
private static int CompareByValue(KeyValuePair<int, string> x, KeyValuePair<int, string> y)
{
    return x.Value.CompareTo(y.Value);
}

为什么下面的条件运算符代码块不能编译:

Comparison<KeyValuePair<int, string>> sortMethod;
sortMethod = isSortByActualValue ? CompareByKey : CompareByValue;

编译器错误:“无法确定条件表达式的类型,因为‘方法组’和‘方法组’之间没有隐式转换”

但是,使用 if-else 的等效代码块没有任何问题:

Comparison<KeyValuePair<int, string>> sortMethod;
if (isSortByActualValue)
    sortMethod = CompareByKey;
else
    sortMethod = CompareByValue;

(以上两个作业都很好)

如果我转换比较委托,条件运算符也是如此:

Comparison<KeyValuePair<int, string>> sortMethod;
sortMethod = isSortByActualValue ? (Comparison<KeyValuePair<int, string>>) CompareByKey : CompareByValue;

(在上面的作业中一切都很好,当施放时,即使施放只是在真实的部分上)

【问题讨论】:

  • CompareByAcutalValue 和 CompareByDisplayValue 是如何定义的?您只显示 CompareByKey 和 CompareByValue 的定义。
  • 为了清晰起见,我对我帖子中的代码 sn-p 进行了编辑。我没有意识到我只是部分更改了(方法的)名称。感谢 Eric,我已将所有对 CompareByActualValue 的引用更新为 CompareByKey(并将 CompareByDisplayValue 更新为 CompareByValue)。

标签: c# .net visual-studio ternary-operator conditional-operator


【解决方案1】:

如果你有一个像CompareByKey 这样的表达式,它没有任何特定的.Net 类型,但有一个特殊的类型“方法组”。那是因为您可以有几种称为CompareByKey 的方法,但不清楚您想要哪一种(即使您只有一种方法,它的工作原理也完全相同)。此外,还不清楚您想要什么委托类型,例如Comparison&lt;KeyValuePair&lt;int, string&gt;&gt;Func&lt;KeyValuePair&lt;int, string&gt;, int&gt;

你可以用方法组做什么?您可以使用它们显式创建委托 (new Comparison&lt;KeyValuePair&lt;int, string&gt;&gt;(CompareByKey)),并且它们也可以隐式转换为委托。这就是您的 if 版本有效的原因。

那么,这与您的问题有什么关系?当您有条件运算符时,编译器必须确定整个表达式的类型,并且它不能使用您分配给它的变量的类型(这不是 C# 中类型推断的工作方式)。并且由于这两个表达式都是方法组,并且方法组被视为不同的类型,彼此之间没有隐式转换,因此无法确定整个表达式的类型。这就是您收到错误的原因。

您已经找到了解决方法:要么不使用条件运算符,要么使用强制转换(或委托构造函数)显式指定其中一个操作数的类型。

【讨论】:

    【解决方案2】:

    错误方法实际上说明了一切,但不是很直观。如果您使用方法名称而不调用该方法,则您正在处理一个方法组。 “组”,因为方法可以被重载,并且名称可以指示任何重载的方法。

    现在,方法组可以隐式转换为具有匹配签名的委托,这就是您在 if 中的分配有效的原因。

    到目前为止,一切都很好。但是,条件运算符?: 需要推导出一个通用类型,它的第二个和第三个参数可以隐式转换为该类型,并且它不考虑所有的转换(这会产生多种问题)。它只是查看两个参数是否具有相同的类型,或者一个是否可以隐式转换为另一个。

    这里不是这样:虽然两个参数都是方法组,但它们实际上是不同具有不同类型的方法组,您不能将一个方法组转换为另一个方法组。尽管两者都可以很容易地转换为委托,但编译器禁止这种用法。

    顺便说一句,其他类型也是如此:

    object = someBool ? "" : New List<Integer>();
    

    由于同样的原因也无法编译。同样,我们可以通过将任一参数显式转换为公共基类型来进行编译:

    object = someBool ? (object) "" : New List<Integer>();
    

    【讨论】:

    • 那么为什么isSortByActualValue ? CompareByKey : CompareByKey 不编译呢?他们不是同一个方法组吗?
    • @svick 不存在从方法组到方法组的转换,无论方法组如何。我应该更清楚地说明这一点,这是一个相当特殊的情况,因为没有普通类型缺少这种转换。我不知道这在 C# 规范中是如何精确说明的。
    • +1,感谢您用另一个包含条件运算符的示例进行解释。感觉编译器对推断正确类型的困惑很有意义,尤其是当第二个和第三个参数可能属于不同(但相关)的类型时。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-22
    • 1970-01-01
    • 2010-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多