5

的比较方法给定两个实现:条件运算符和比较代表

// 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 d OES没有任何问题:

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; 

(都好于上面的作业,即使只是在真实的部分施放)

+2

如何定义CompareByAcutalValue和CompareByDisplayValue?您只显示CompareByKey和CompareByValue的定义。 – 2012-02-28 19:30:37

+0

我发布的代码片段是为了清晰起见而编辑的。我没有意识到我只是部分改变了方法的名称。感谢Eric,我已经将CompareByActualValue的所有引用更新为CompareByKey(并将CompareByDisplayValue更新为CompareByValue)。 – Arun 2012-02-28 19:42:23

回答

7

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

现在,方法组可隐式转换为具有匹配签名的委托,这就是为什么您的作业在if工作。

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

这不是这里的情况:尽管这两个参数是方法组,它们实际上是与不同类型不同方法组,你不能将一个方法组到另一个。即使两者都可以很容易地转换成一个委托,编译器禁止这种用法。

这同样适用于其他类型的真实,顺便说一句:

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

也无法编译,出于同样的原因。再次,我们可以通过明确铸造其中一个参数,以一个共同的基本类型此编译:

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

+1,但我会改变“需要推断它的第二和第三个参数的类型”为“需要推导出一个通用类型,其第二个和第三个参数可以被隐式转换” – phoog 2012-02-28 19:50:20

+0

那么为什么不'isSortByActualValue ? CompareByKey:CompareByKey'编译?他们不是同一个方法组吗? – svick 2012-02-28 19:56:11

+0

@svick无论方法组如何,都不存在从方法组到方法组的转换。我应该做得更清楚一点,这是一个相当特殊的情况,因为没有普通的类型没有这种转换。我不知道C#规范中是如何精确描述的。 – 2012-02-28 20:00:15

3

如果你有一个像你CompareByKey的表达,它不具有任何特定的.NET类型,但一个特殊类型的“方法组”。这是因为你可能有几种方法叫做CompareByKey,你不知道你想要哪一种(即使你只有一种方法,它也是一样的)。另外,您还不清楚代理类型是什么,例如Comparison<KeyValuePair<int, string>>Func<KeyValuePair<int, string>, int>

你可以用方法组做什么?您可以使用它们明确创建委托(new Comparison<KeyValuePair<int, string>>(CompareByKey)),并且它们也可以隐式转换为委托。这就是您的if版本正常工作的原因。

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

您已经找到了一个修复:要么不使用条件运算符,要么通过使用转换(或委托构造函数)明确指定其中一个操作数的类型。