我收集了一些极端案例和脑筋急转弯,总是想听到更多。这个页面只涵盖了c#语言的一些细节,但我也发现了。net核心的东西也很有趣。例如,这里有一个没有在页面上,但我觉得不可思议:

string x = new string(new char[0]);
string y = new string(new char[0]);
Console.WriteLine(object.ReferenceEquals(x, y));

我希望输出False -毕竟,“new”(具有引用类型)总是创建一个新对象,不是吗?c#和CLI的规范都表明应该这样做。嗯,在这个特殊情况下不是这样。它输出True,并且在我测试过的框架的每个版本上都是这样。(不可否认,我还没有在Mono上尝试过……)

只是为了澄清,这只是我正在寻找的事情的一个例子-我并不是特别寻找对这个奇怪现象的讨论/解释。(这和普通的弦乐实习不一样;特别地,当调用构造函数时,字符串实习通常不会发生。)我真的是在要求类似的奇怪行为。

还有其他的宝藏吗?


当前回答

以下选项无效:

if (something)
    doit();
else
    var v = 1 + 2;

但这是可行的:

if (something)
    doit();
else {
    var v = 1 + 2;
}

其他回答

以下选项无效:

if (something)
    doit();
else
    var v = 1 + 2;

但这是可行的:

if (something)
    doit();
else {
    var v = 1 + 2;
}

今天刚发现一件小玩意儿

public class Base
{
   public virtual void Initialize(dynamic stuff) { 
   //...
   }
}
public class Derived:Base
{
   public override void Initialize(dynamic stuff) {
   base.Initialize(stuff);
   //...
   }
}

这会引发编译错误。

对方法'Initialize'的调用需要动态分派,但不能这样做,因为它是基本访问表达式的一部分。考虑强制转换动态参数或取消基本访问。

如果我写底。初始化(stuff as object);它工作得很完美,但这似乎是一个“神奇的词”,因为它的功能完全相同,一切仍然是动态的……

这是我最近才发现的一个……

interface IFoo
{
   string Message {get;}
}
...
IFoo obj = new IFoo("abc");
Console.WriteLine(obj.Message);

乍一看,上述做法很疯狂,但实际上是合法的。不,真的(虽然我错过了一个关键部分,但它不是任何像“添加一个称为IFoo的类”或“添加一个使用别名将IFoo指向一个类”这样的俗套)。

看看你是否能找出原因:谁说你不能实例化一个接口?

想想这个奇怪的例子:

public interface MyInterface {
  void Method();
}
public class Base {
  public void Method() { }
}
public class Derived : Base, MyInterface { }

如果在同一个程序集中声明Base和Derived,编译器将使Base::方法为虚拟且密封(在CIL中),即使Base没有实现接口。

如果Base和Derived在不同的程序集中,编译Derived程序集时,编译器不会更改其他程序集,因此它将在Derived中引入一个成员,该成员将是MyInterface::Method的显式实现,它只会将调用委托给Base::Method。

编译器必须这样做,以支持与接口有关的多态分派,即它必须使该方法为虚拟。

银行家的舍入。

这不是一个编译器错误或故障,但肯定是一个奇怪的极端情况…

. net框架采用了一种被称为银行家舍入的方案或舍入。

在银行家的四舍五入中,0.5的数字四舍五入到最接近的偶数,所以

Math.Round(-0.5) == 0
Math.Round(0.5) == 0
Math.Round(1.5) == 2
Math.Round(2.5) == 2
etc...

这可能会导致基于更广为人知的四舍五入的财务计算中出现一些意想不到的错误。

Visual Basic也是如此。