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

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

还有其他的宝藏吗?


当前回答

以下是我的一些建议:

当调用实例方法而不抛出NullReferenceException时,此值可以为null 不必为枚举定义默认枚举值

首先简单一点: enum NoZero { Number = 1 }

        public bool ReturnsFalse()
        {
            //The default value is not defined!
            return Enum.IsDefined(typeof (NoZero), default(NoZero));
        }

下面的代码实际上可以打印真!

 internal sealed class Strange
{
    public void Foo()
    {
        Console.WriteLine(this == null);
    }
}

一段简单的客户端代码将导致这样的结果 HelloDelegate(奇怪的条);

public class Program
{
    [STAThread()]
    public static void Main(string[] args)
    {
        Strange bar = null;
        var hello = new DynamicMethod("ThisIsNull",
            typeof(void), new[] { typeof(Strange) },
         typeof(Strange).Module);
        ILGenerator il = hello.GetILGenerator(256);
        il.Emit(OpCodes.Ldarg_0);
        var foo = typeof(Strange).GetMethod("Foo");
        il.Emit(OpCodes.Call, foo);
        il.Emit(OpCodes.Ret);
        var print = (HelloDelegate)hello.CreateDelegate(typeof(HelloDelegate));
        print(bar);
        Console.ReadLine();
    }
}

这在大多数语言中都是正确的,只要调用实例方法时不使用对象的状态。只有在访问对象的状态时才解除引用

其他回答

几年前,在制定忠诚度计划时,我们遇到了一个关于给予客户积分数量的问题。这个问题与将double类型转换为int类型有关。

代码如下:

double d = 13.6;

int i1 = Convert.ToInt32(d);
int i2 = (int)d;

i1 == i2吗?

结果是i1 != i2。 由于Convert和cast运算符的舍入策略不同,实际值为:

i1 == 14
i2 == 13

调用Math. ceiling()或Math. floor()(或Math. ceiling())总是更好。用符合我们要求的midpointrsurround进行四舍五入)

int i1 = Convert.ToInt32( Math.Ceiling(d) );
int i2 = (int) Math.Ceiling(d);

在我们使用的API中,返回域对象的方法可能返回一个特殊的“空对象”。在此实现中,比较运算符和Equals()方法将被重写,如果与null进行比较则返回true。

所以这个API的用户可能会有这样的代码:

return test != null ? test : GetDefault();

或者更啰嗦一点,像这样:

if (test == null)
    return GetDefault();
return test;

其中GetDefault()是一个方法,返回一些我们想要使用的默认值,而不是null。当我使用ReSharper并按照它的建议重写这其中的任何一个时,我感到惊讶:

return test ?? GetDefault();

如果测试对象是从API返回的空对象,而不是一个正确的空对象,那么代码的行为现在已经改变,因为空合并操作符实际上检查null,而不是运行operator=或Equals()。

这是我迄今为止见过的最不寻常的一个(当然除了这里的!)

public class Turtle<T> where T : Turtle<T>
{
}

它允许你声明它,但没有真正的用途,因为它总是要求你用另一个Turtle来包装你塞在中间的任何类。

(笑话)我猜是乌龟一直往下走……[/笑话]

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

static int x = 0;

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

static void Main() { Foo(); }

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。