灵感来自这个问题.
简短版本:M(dynamic arg)如果只有一个重载M或所有重载M具有相同的返回类型,为什么编译器不能找出编译时类型?
根据规范,§7.6.5:
如果至少满足下列条件之一,则动态绑定调用表达式(第7.2.2节):
primary-expression具有编译时类型dynamic.
可选参数列表的至少一个参数具有编译时类型dynamic,而primary-expression没有委托类型.
这是有道理的
class Foo {
public int M(string s) { return 0; }
public string M(int s) { return String.Empty; }
}
Run Code Online (Sandbox Code Playgroud)
编译器无法弄清楚编译时的类型
dynamic d = // dynamic
var x = new Foo().M(d);
Run Code Online (Sandbox Code Playgroud)
因为直到运行时才会知道M调用了哪个重载.
但是,为什么编译器无法计算编译时类型,如果M只有一个重载或所有重载M返回相同的类型?
我想了解为什么规范不允许编译器在编译时静态地键入这些表达式.
Eri*_*ert 22
更新:这个问题是我的博客在2012年10月22日的主题.谢谢你这个好问题!
M(dynamic_expression)如果只有一个M的重载或者M的所有重载具有相同的返回类型,为什么编译器不能找出编译类型?
编译器可以找出编译时类型; 编译时类型是动态的,编译器成功地表明了这一点.
我想你想问的问题是:
为什么编译时类型
M(dynamic_expression)始终是动态的,即使在极少且不太可能的情况下,您正在对方法M进行完全不必要的动态调用,而不管参数类型如何都会被选中?
当你说出这样的问题时,它有点自己回答.:-)
原因一:
你想象的案例很少见; 为了使编译器能够进行您描述的推理,必须知道足够的信息,以便编译器可以对表达式进行几乎完整的静态类型分析.但是,如果您处于那种情况,那么为什么您首先使用动态?你会做得更好,只需说:
object d = whatever;
Foo foo = new Foo();
int x = (d is string) ? foo.M((string)d) : foo((int)d);
Run Code Online (Sandbox Code Playgroud)
显然,如果M只有一个重载,则更容易:将对象转换为所需类型.如果它在运行时失败,因为它很糟糕,那么动态也会失败!
在这些场景中,首先根本不需要动态,为什么我们会在编译器中进行大量昂贵且困难的类型推理工作,以启用我们不希望您首先使用动态的场景?
原因二:
假设我们确实说如果静态地知道方法组包含一个方法,则重载决策具有非常特殊的规则.大.现在我们刚刚为语言添加了一种新的脆弱性.现在添加一个新的重载会将调用的返回类型更改为完全不同的类型 - 这种类型不仅会导致动态语义,还会导致框值类型.但等等,它变得更糟!
// Foo corporation:
class B
{
}
// Bar corporation:
class D : B
{
public int M(int x) { return x; }
}
// Baz corporation:
dynamic dyn = whatever;
D d = new D();
var q = d.M(dyn);
Run Code Online (Sandbox Code Playgroud)
让我们假设我们实现你的特性需要,并根据你的逻辑推断q是int.现在Foo公司补充道:
class B
{
public string M(string x) { return x; }
}
Run Code Online (Sandbox Code Playgroud)
突然,当Baz公司重新编译他们的代码时,突然q的类型悄然变为动态,因为我们在编译时不知道dyn不是字符串.这是静态分析中一个奇怪而意想不到的变化!第三方添加新的方法,为什么要到一个基类引起的局部变量的类型在一个完全不同的方法中更改了在不同的公司,甚至不直接使用B中的公司写了一个完全不同的类,但只能通过D?
这是脆性基类问题的一种新形式,我们寻求最小化C#中的脆弱基类问题.
或者,如果相反Foo公司说:
class B
{
protected string M(string x) { return x; }
}
Run Code Online (Sandbox Code Playgroud)
现在,根据你的逻辑,
var q = d.M(dyn);
Run Code Online (Sandbox Code Playgroud)
当上面的代码在继承自D的类型之外时,给出q类型int ,但是
var q = this.M(dyn);
Run Code Online (Sandbox Code Playgroud)
给出q的类型为动态时内,从d继承的类型!作为开发人员,我会发现这非常令人惊讶.
原因三:
C#中已经有太多的聪明才智了.我们的目标不是构建一个逻辑引擎,该逻辑引擎可以针对特定程序对所有可能的值进行所有可能的类型限制.我们更倾向于拥有一般的,可理解的,易于理解的规则,这些规则可以轻松地写下来并且没有错误地实现.规范已经有八百页了,编写一个无错误的编译器是非常困难的.让我们不要让它变得更难.更不用说测试所有那些疯狂案件的费用了.
原因四:
此外:该语言为您提供了许多利用静态类型分析器的机会.如果您使用的是动态,则特别要求该分析器将其操作推迟到运行时.使用"在编译时停止执行静态类型分析"功能导致静态类型分析在编译时不能很好地工作应该不足为奇.
| 归档时间: |
|
| 查看次数: |
1022 次 |
| 最近记录: |