developer tip

특별한 경우로 빈 문자열?

copycodes 2021. 1. 8. 08:32
반응형

특별한 경우로 빈 문자열?


나는 Jon Skeet의 퀴즈를 읽고 첫 번째 샘플이 작동하는 동안 두 번째 샘플이 작동하지 않는 이유가 궁금했습니다.

이것이 왜 산출됩니까 true?

object x = new string("".ToArray());
object y = new string("".ToArray());
Console.WriteLine(x == y); //true

그러나 이것은 :

var k="k";
//string.intern(k); // doesn't help
object x = new string(k.ToArray());
object y = new string(k.ToArray());
Console.WriteLine(x == y); //false

vs2010과 함께 fw 4.5를 사용하고 있습니다.

운 좋게도 vs2005가 설치되어 있습니다.

여기에 이미지 설명 입력


다음은 Eric Lippert의 블로그 게시물로 String interning 및 String.Empty 의 질문에 대한 답변 입니다.

그는 비슷한 상황을 설명하고 있습니다.

object obj = "Int32";
string str1 = "Int32";
string str2 = typeof(int).Name;
Console.WriteLine(obj == str1); // true
Console.WriteLine(str1 == str2); // true
Console.WriteLine(obj == str2); // false !?

그래서 아이디어는 인턴이 인턴을 string하더라도 특정 인스턴스가 하나만 있다는 것을 의미하지는 않습니다 . 기본적으로 컴파일 시간 리터럴 만 인턴됩니다 . 이는 다음 코드가 true를 인쇄 함을 의미합니다.

var k1 = "k";
object k2 = "k";
Console.WriteLine(k1 == k2);

그러나 생성자 사용 , 객체 호출 ,를 사용하는 "k"런타임에 프로그래밍 방식 으로 콘텐츠가 포함 된 문자열을 만들려고하면 기본적으로 인턴 된 문자열이 생성되지 않습니다. 이것은 거짓을 인쇄합니다.string(char[])ToString()StringBuilder

var k1 = "k";
object k2 = new string("k".ToCharArray());
Console.WriteLine(k1 == k2);

왜? 런타임에 인턴 문자열이 비싸기 때문입니다.

공짜 점심 같은 건 없다.

(...)

요컨대, 일반적으로 모든 문자열을 인턴하는 것은 가치가 없습니다.

빈 문자열의 다른 동작에 대해 :

.NET 런타임의 일부 버전은 런타임에 빈 문자열을 자동으로 인턴하지만 일부는 그렇지 않습니다!


인턴 있습니다 새로운 코드의 두 번째 블록의 문자열하는 않는 그들을 동일합니다.

var k="k";
object x = string.Intern(new string(k.ToArray()));
object y = string.Intern(new string(k.ToArray()));
Console.WriteLine(x == y); //true

빈 문자열을 자동으로 인턴하는 것처럼 보이지만 비어 있지 않은 문자열은 명시 적으로 수행되지 않는 한 인턴되지 않습니다 (또는 항상 인턴되는 리터럴 문자열입니다).

예, 빈 문자열은 특수한 경우로 처리되고 자동으로 인턴됩니다. 아마도 검사가 너무 사소하여 실제 성능 저하를 추가하지 않기 때문일 것입니다 (길이가 0 인 문자열은 빈 문자열이고 다른 빈 문자열과 동일합니다. 다른 모든 문자열은 길이뿐만 아니라 문자를 봐야합니다).


첫 번째 경우는 동일한 객체 ( String.Empty)에 대한 2 개의 참조를 비교합니다 . operator==2 개의 object변수를 호출 하면 참조에 의한 비교가 발생하고 true.

두 번째 경우는 문자열 클래스의 두 가지 다른 인스턴스를 생성합니다. 그들의 참조 비교는false

당신이 줄 경우 string에 유형 xy두 번째 경우에 string.operator==오버라이드가 호출되고 비교 제공true

두 경우 모두에서 문자열 인턴을 직접 처리하지 않습니다. 비교하는 문자열 객체는 string(char[])생성자를 사용하여 생성됩니다. 분명히 그 생성자는 string.Empty빈 배열을 인수로 사용하여 호출 될 때 필드 의 값을 반환하도록 설계되었습니다 .

MarcinJuraszek이 게시 한 답변은 스트링 인턴에 대해 논의 하는 Lippert의 블로그 를 참조합니다. 이 블로그 게시물은 문자열 클래스 사용의 다른 경우에 대해 설명합니다. 앞서 언급 한 Lippert의 블로그에서 다음 예를 고려하십시오.

object obj = "";
string str1 = "";
string str2 = String.Empty;
Console.WriteLine(obj == str1); // true
Console.WriteLine(str1 == str2); // true
Console.WriteLine(obj == str2); // sometimes true, sometimes false?!

What we see here is that the assignment from the empty string literal ("") is not guaranteed to produce the reference to the static readonly System.String.Empty field.

Let's look at the IL for the object x = new string("".ToArray()); expression:

IL_0001:  ldstr      ""
IL_0006:  call       !!0[] [System.Core]System.Linq.Enumerable::ToArray<char>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_000b:  newobj     instance void [mscorlib]System.String::.ctor(char[])
IL_0010:  stloc.0

The interning may (or may not) happen at the IL_0001 line. Whether the literal is interned or not, the ToArray() method produces a new empty array and the String::.ctor(char[]) gives us String.Empty.

What we see here is not the special case of string.Empty but rather is one of the side effects of the string class being reference type and immutable at the same time. There are other immutable framework types which have predefined values with similar semantics (like DateTime.MinValue). But as far as I know such framework types are defined as struct unlike the string which is a reference type. The value types are totally different story... It does not make sense to return some fixed predefined type instance from a mutable class constructor (the calling code will be able to change that instance and cause the unpredictable behavior of the type). So the reference types whose constructors do not always return new instances may exist provided that those types are immutable. I am not aware of other such types in the framework though, except the string.


My hypothesis is why the first one yields true while the 2nd yields false:

The first result my be an optimization, take the following code code

Enumerable.Empty<char>() == Enumerable.Empty<char>() // true

So, suppose the ToArray method returns Enumerable.Empty<char>() when the string is empty, this would explain why the first result yields true and the 2nd doesn't, as it's doing a reference check.


According to http://msdn.microsoft.com/en-us/library/system.string.intern(v=vs.110).aspx

In the .NET Framework 3.5 Service Pack 1, the Intern method reverts to its behavior in the .NET Framework 1.0 and 1.1 with regard to interning the empty string...

...In the .NET Framework 1.0, .NET Framework 1.1, and .NET Framework 3.5 SP1, ~empty strings~ are equal

This means, empty strings are both interned by default, even when constructing from an empty array, and are therefore equal.

Furthermore:

The .NET Framework version 2.0 introduces the CompilationRelaxations.NoStringInterning enumeration member

이것은 @BenM이 제안한 것처럼 Intern 함수를 명시 적으로 사용하고 싶지만 일관된 비교 방법을 만드는 방법을 제공합니다.

발생하는 권투를 감안할 때 string.Equals대신 사용할 수도 있습니다.==


이것이 내가 문자열 비교에 대한 Jon Skeet의 답변을 참조하는 이유라고 생각합니다.

string.Equals () 및 == 연산자가 실제로 동일합니까?

        object x1 = new StringBuilder("").ToString().ToArray();
        object y1 = new StringBuilder("").ToString().ToArray();
        Console.WriteLine(x1 == y1); //true

        Console.WriteLine("Address x1:" + Get(x1));
        Console.WriteLine("Address y1:" + Get(y1));

        var k = "k";
        //string.intern(k); // doesn't help
        object x = new string(k.ToArray());
        object y = new string(k.ToArray());
        Console.WriteLine(x == y); //false

        Console.WriteLine("Address x:" + Get(x));
        Console.WriteLine("Address y:" + Get(y));

        Console.Read(); 

산출

False
Address x1:0x2613E5
Address y1:0x2613E5
False
Address x:0x2613E5
Address y:0x2613E5

빈 문자열이 항상 동일한 객체를 반환하는 특별한 경우가 있으며 이것이이 경우 객체가 동일한 지 비교할 때이 경우 참입니다.

[편집] : 이전 코드는 객체 대신 문자열 비교기를 사용했습니다.

object a = "s";
object b = "d";

a = ((string)a).Replace("s", "");
b = ((string)b).Replace("d", "");

Console.WriteLine(a == b);

object c = "sa";
object d = "da";

c = ((string)c).Replace("s", "");
d = ((string)d).Replace("d", "");

Console.WriteLine(c == d);

c = ((string)c).Replace("a", "");
d = ((string)d).Replace("a", "");

Console.WriteLine(c == d);

결과

True
False
True

참조 URL : https://stackoverflow.com/questions/22138144/empty-string-as-a-special-case

반응형