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

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

还有其他的宝藏吗?


当前回答

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

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

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

    [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);
        }
    }

其他回答

有趣的是,当我第一次看到它时,我认为这是c#编译器正在检查的东西,但即使你直接发出IL来消除任何干扰的机会,它仍然会发生,这意味着它真的是newobj操作代码正在进行检查。

var method = new DynamicMethod("Test", null, null);
var il = method.GetILGenerator();

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Newarr, typeof(char));
il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) }));

il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Newarr, typeof(char));
il.Emit(OpCodes.Newobj, typeof(string).GetConstructor(new[] { typeof(char[]) }));

il.Emit(OpCodes.Call, typeof(object).GetMethod("ReferenceEquals"));
il.Emit(OpCodes.Box, typeof(bool));
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(object) }));

il.Emit(OpCodes.Ret);

method.Invoke(null, null);

如果检查string,它也等于true。这意味着这个操作代码必须有特殊的行为来实习空字符串。

c#中的作用域有时真的很奇怪。让我给你们举个例子:

if (true)
{
   OleDbCommand command = SQLServer.CreateCommand();
}

OleDbCommand command = SQLServer.CreateCommand();

编译失败,因为命令被重新声明?在stackoverflow的这个帖子和我的博客中,有一些有趣的猜测,为什么它会这样工作。

VB。NET、可空值和三元操作符:

Dim i As Integer? = If(True, Nothing, 5)

这花了我一些时间来调试,因为我希望I包含Nothing。

i到底包含了什么?0.

这是令人惊讶的,但实际上是“正确的”行为:在VB中没有。NET与CLR中的null并不完全相同:对于值类型T,没有值可以表示null或默认值(T),这取决于上下文。在上面的例子中,If将Integer推断为Nothing和5的常见类型,因此,在这种情况下,Nothing意味着0。

c#无障碍谜题


下面的派生类正在从它的基类中访问一个私有字段,编译器会默默地查看另一端:

public class Derived : Base
{
    public int BrokenAccess()
    {
        return base.m_basePrivateField;
    }
}

这个领域确实是私有的:

private int m_basePrivateField = 0;

想猜猜我们如何编译这样的代码吗?

.

.

.

.

.

.

.

回答


诀窍是将Derived声明为Base的内部类:

public class Base
{
    private int m_basePrivateField = 0;

    public class Derived : Base
    {
        public int BrokenAccess()
        {
            return base.m_basePrivateField;
        }
    }
}

内部类可以完全访问外部类成员。在这种情况下,内部类也恰好派生自外部类。这允许我们“打破”私有成员的封装。

这一点很简单,但我还是觉得很有趣。调用Foo后x的值是多少?

static int x = 0;

public static void Foo()
{
    try { return; }
    finally { x = 1; }
}

static void Main() { Foo(); }