我收集了一些极端案例和脑筋急转弯,总是想听到更多。这个页面只涵盖了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上尝试过……)

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

还有其他的宝藏吗?


当前回答

我不久前问了一个问题:

条件运算符不能隐式强制转换?

考虑到:

Bool aBoolValue;

其中aBoolValue被赋值为True或False;

以下文件将无法编译:

Byte aByteValue = aBoolValue ? 1 : 0;

但这将:

Int anIntValue = aBoolValue ? 1 : 0;

提供的答案也很好。

其他回答

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

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

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

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

下面是一个示例,说明如何创建导致错误消息“试图读写受保护内存”的结构。这通常表明其他记忆被破坏了。” 成功与失败的差别非常细微。

下面的单元测试演示了这个问题。

看看你能不能找出问题出在哪里。

    [Test]
    public void Test()
    {
        var bar = new MyClass
        {
            Foo = 500
        };
        bar.Foo += 500;

        Assert.That(bar.Foo.Value.Amount, Is.EqualTo(1000));
    }

    private class MyClass
    {
        public MyStruct? Foo { get; set; }
    }

    private struct MyStruct
    {
        public decimal Amount { get; private set; }

        public MyStruct(decimal amount) : this()
        {
            Amount = amount;
        }

        public static MyStruct operator +(MyStruct x, MyStruct y)
        {
            return new MyStruct(x.Amount + y.Amount);
        }

        public static MyStruct operator +(MyStruct x, decimal y)
        {
            return new MyStruct(x.Amount + y);
        }

        public static implicit operator MyStruct(int value)
        {
            return new MyStruct(value);
        }

        public static implicit operator MyStruct(decimal value)
        {
            return new MyStruct(value);
        }
    }

想想这个奇怪的例子:

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。

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

c#中有一些非常令人兴奋的东西,它处理闭包的方式。

它不是将堆栈变量值复制到闭包自由变量,而是执行预处理器的魔法,将变量的所有出现都包装到一个对象中,从而将其移出堆栈-直接移到堆中!:)

我想,这使得c#甚至比ML本身(使用堆栈值复制AFAIK)更功能完备(或lambda-complete huh)。f#和c#一样也有这个特性。

这给我带来了很多快乐,谢谢你们!

但这并不是一个奇怪的或极端的情况……但是基于堆栈的虚拟机语言真的出乎意料:)

Public Class Item
   Public ID As Guid
   Public Text As String

   Public Sub New(ByVal id As Guid, ByVal name As String)
      Me.ID = id
      Me.Text = name
   End Sub
End Class

Public Sub Load(sender As Object, e As EventArgs) Handles Me.Load
   Dim box As New ComboBox
   Me.Controls.Add(box)          'Sorry I forgot this line the first time.'
   Dim h As IntPtr = box.Handle  'Im not sure you need this but you might.'
   Try
      box.Items.Add(New Item(Guid.Empty, Nothing))
   Catch ex As Exception
      MsgBox(ex.ToString())
   End Try
End Sub

输出为“试图读取受保护的内存。”这表明其他记忆已经被破坏了。”