简体   繁体   English

Object.ReferenceEquals为两个不同的对象输出true

[英]Object.ReferenceEquals prints true for two different objects

How is the below code is printing true ? 以下代码如何打印true

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

I expected this to print False , because I expected two separate objects to be constructed and then their references compared. 我希望这打印False ,因为我期望构建两个单独的对象,然后比较它们的引用。

This is an undocumented (as far as I'm aware) optimization in the CLR. 这是CLR中未记录的(据我所知)优化。 It's very odd, but yes: the new operator is returning the same reference from two calls. 这很奇怪,但是: new运算符从两个调用返回相同的引用。

It appears to be implemented in CoreCLR as well on Linux (and even on Mono). 它似乎也在Linux上(甚至在Mono上)在CoreCLR中实现。

The string constructor is the only example of this that I've seen, although as noted in comments you can provoke it with other constructor overloads. 字符串构造函数是我见过的唯一一个例子,尽管如评论中所述,你可以用其他构造函数重载来激发它。

I'm convinced it's an optimization in the CLR, as the IL is as you'd expect it - and moving the constructor call into a different method doesn't change things either: 我确信它是CLR中的优化,因为IL正如您所期望的那样 - 并且将构造函数调用移动到另一个方法中也不会改变:

using System;

public class Test
{
    static void Main()
    {
        // Declaring as object to avoid using the == overload in string
        object x = CreateString(new char[0]);
        object y = CreateString(new char[0]);
        object z = CreateString(new char[1]);
        Console.WriteLine(x == y); // True
        Console.WriteLine(x == z); // False        
    }

    static string CreateString(char[] c)
    {
        return new string(c);
    }
}

Now that the CLR is open source, we can find out where this is performed. 现在CLR是开源的,我们可以找到它的执行位置。 It appears to be in object.cpp - if you search for occurrences of GetEmptyString you'll see it used in various cases when a string of length 0 is being constructed. 它似乎在object.cpp - 如果你搜索GetEmptyString出现,你会看到它在构造长度为0的字符串的各种情况下使用。

This happens because special case is made for constructing empty strings from empty char arrays. 发生这种情况是因为从空char数组构造空字符串的特殊情况。 The string constructor returns string.Empty for empty strings constructed in this way: 字符串构造函数返回以这种方式构造的空字符串的string.Empty

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

From the reference source for string (this is the constructor for a char* parameter): 字符串引用源 (这是char*参数的构造函数):

[System.Security.SecurityCritical]  // auto-generated
private unsafe String CtorCharPtr(char *ptr)
{
    if (ptr == null)
        return String.Empty;

#if !FEATURE_PAL
    if (ptr < (char*)64000)
        throw new ArgumentException(Environment.GetResourceString("Arg_MustBeStringPtrNotAtom"));
#endif // FEATURE_PAL

    Contract.Assert(this == null, "this == null");        // this is the string constructor, we allocate it

    try {
        int count = wcslen(ptr);
        if (count == 0)
            return String.Empty;

        String result = FastAllocateString(count);
        fixed (char *dest = result)
            wstrcpy(dest, ptr, count);
        return result;
    }
    catch (NullReferenceException) {
        throw new ArgumentOutOfRangeException("ptr", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
    }
}

And also (this is the constructor for a char[] parameter): 而且(这是char[]参数的构造函数):

    [System.Security.SecuritySafeCritical]  // auto-generated
    private String CtorCharArray(char [] value)
    {
        if (value != null && value.Length != 0) {
            String result = FastAllocateString(value.Length);

            unsafe {
                fixed (char * dest = result, source = value) {
                    wstrcpy(dest, source, value.Length);
                }
            }
            return result;
        }
        else
            return String.Empty;
    }

Note the lines: 注意这些行:

        if (count == 0)
            return String.Empty;

and

        else
            return String.Empty;

That is because object.Equals first checks on reference equality, and then calls Equals on the first variable ( x ). 这是因为object.Equals首先检查引用相等性,然后在第一个变量( x )上调用Equals

string.Equals checks against the actual value of a string (using the current culture settings, which may influence the comparison), not only the reference, so it returns true since both objects have the same value. string.Equals检查字符串的实际值(使用当前文化设置,这可能会影响比较),而不仅仅是引用,因此它返回true因为两个对象具有相同的值。


For your edit: it seems that the CLRr does some magic and tries to evaluate your new string(char[0]) , so it can be interned. 对于你的编辑:似乎CLRr做了一些魔法并试图评估你的new string(char[0]) ,所以它可以被实习。 You can see the same behavior if you set x to "" . 如果将x设置为""则可以看到相同的行为。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Object.ReferenceEquals对于匹配的字符串返回true - Object.ReferenceEquals returns true for matching strings object.ReferenceEquals或==运算符? - object.ReferenceEquals or == operator? Object.ReferenceEquals永远不会命中 - Object.ReferenceEquals never hit IEnumerable、Where 和 Object.ReferenceEquals 的问题 - Issue with IEnumerable, Where, and Object.ReferenceEquals &#39;Object.ReferenceEquals&#39;始终为false,因为它使用值类型进行调用 - 'Object.ReferenceEquals' is always false because it is called with a value type Assert.ReferenceEquals()在Visual Studio Test中Object.ReferenceEquals()返回&#39;false&#39;的位置 - Assert.ReferenceEquals() Passes where Object.ReferenceEquals() returns 'false' in Visual Studio Test c#中Object.Equals(object,object)和Object.ReferenceEquals(object,object)之间的区别 - difference between Object.Equals(object,object) and Object.ReferenceEquals(object,object) in c# C#operator ==,StringBuilder.Equals,Object.Equals和Object.ReferenceEquals之间的差异 - C# Differences between operator ==, StringBuilder.Equals, Object.Equals and Object.ReferenceEquals 为什么我要在Equals覆盖中执行object.ReferenceEquals(null,this)? - Why would I ever want to do object.ReferenceEquals(null, this) in Equals override? 参考平等性能差异? ((object)obj1 ==(object)obj2)vs。object.ReferenceEquals(obj1,obj2) - Reference equality performance difference? ((object)obj1 == (object)obj2) vs. object.ReferenceEquals( obj1, obj2 )
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM