programing

문자열입니다.()와 == 연산자가 정말 동일합니까?

testmans 2023. 7. 29. 08:17
반응형

문자열입니다.()와 == 연산자가 정말 동일합니까?

그들은 정말 똑같습니까?오늘, 저는 이 문제에 부딪혔습니다.다음은 즉시 창에서 덤프입니다.

?s 
"Category" 
?tvi.Header 
"Category" 
?s == tvi.Header 
false 
?s.Equals(tvi.Header) 
true 
?s == tvi.Header.ToString() 
true 

그래서 둘 다s그리고.tvi.Header하지만 '카테고리'는 포함합니다.== 및 false를 합니다.Equals()truetrue를 합니다.

s문자열로 됩니다.tvi.Header "WPF"입니다.TreeViewItem.Header그렇다면, 왜 그들은 다른 결과를 반환할까요?저는 항상 그것들이 C#에서 상호 교환 가능하다고 생각했습니다.

이유를 설명할 수 있는 사람?

두 가지 차이점:

  • Equals 수 객체의 것인 반면, 은 " " " " " " (즉, 즉 " 재 " 정 " 될 " 수 " 의 " 인 " 있 " 사 " 객 " 되 " 성 " 다 " 시 " 실 " 유 " 따 " 달 " 라 " 반 " 라 " 것 " 질 " 형 " 에 " 형 " 면 " 간 " 며 는 " 의 " 대 " 행 " 은 " 구 " 으 " 상==사용 여부는 객체의 컴파일 시간 유형에 따라 결정됩니다.

      // Avoid getting confused by interning
      object x = new StringBuilder("hello").ToString();
      object y = new StringBuilder("hello").ToString();
      if (x.Equals(y)) // Yes
    
      // The compiler doesn't know to call ==(string, string) so it generates
      // a reference comparision instead
      if (x == y) // No
    
      string xs = (string) x;
      string ys = (string) y;
    
      // Now *this* will call ==(string, string), comparing values appropriately
      if (xs == ys) // Yes
    
  • Equalst null은 예외입니다. == won't null은 예외입니다.

      string x = null;
      string y = null;
    
      if (x.Equals(y)) // NullReferenceException
    
      if (x == y) // Yes
    

다음을 사용하여 후자가 문제가 되는 것을 방지할 수 있습니다.object.Equals:

if (object.Equals(x, y)) // Fine even if x or y is null

질문에 나타나는 명백한 모순은 한 경우에 발생하기 때문에 발생합니다.Equals에서 됩니다.string에는 목어고다경른우는에그리적▁object는경,에.==가 연자가습다에서 됩니다.System.Object활자를 string그리고.object동일성을 서로 다르게 구현합니다(각각 값 대 기준).

이 사실을 넘어서, 어떤 유형이든 정의할 수 있습니다.==그리고.Equals다르게 말하자면, 일반적으로 그것들은 서로 교환할 수 없습니다.

여기에 다은을사예입다니한을 사용한 .double(Joseph Albahari의 노트에서 C# 언어 사양의 § 7.9.2로):

double x = double.NaN;
Console.WriteLine (x == x);         // False
Console.WriteLine (x != x);         // True
Console.WriteLine (x.Equals(x));    // True

그는 계속해서 말합니다.double.Equals(double)방법은 목록과 사전과 함께 올바르게 작동하도록 설계되었습니다.==반면에 연산자는 부동 소수점 유형에 대한 IEEE 754 표준을 따르도록 설계되었습니다.

문자열 동일성을 결정하는 구체적인 경우, 업계 선호도는 다음 중 어느 것도 사용하지 않는 것입니다.==도 아니다string.Equals(string)대부분의 시간.이러한 방법은 두 문자열이 문자별로 동일한지 여부를 결정하며, 이는 거의 올바른 동작이 아닙니다.사용하는 것이 더 좋습니다.string.Equals(string, StringComparison)특정 비교 유형을 지정할 수 있습니다.올바른 비교를 사용하면 많은 잠재적(진단하기 매우 어려운) 버그를 방지할 수 있습니다.

여기 한 가지 예가 있습니다.

string one = "Caf\u00e9";        // U+00E9 LATIN SMALL LETTER E WITH ACUTE
string two = "Cafe\u0301";       // U+0301 COMBINING ACUTE ACCENT
Console.WriteLine(one == two);                                          // False
Console.WriteLine(one.Equals(two));                                     // False
Console.WriteLine(one.Equals(two, StringComparison.InvariantCulture));  // True

이 예에서 두 문자열은 모두 동일한("Cafe") 모양이므로, 네이브(순서적) 동일성을 사용하는 경우 디버깅하기가 매우 어려울 수 있습니다.

C#에는 두 가지 "동등한" 개념이 있습니다.Equals그리고.ReferenceEquals이 접하는 만게될대수의경우업의부분나,,==연산자는 하나 또는 다른 하나(또는 둘 다)를 사용하며, 일반적으로 다음에 대한 검정만 수행합니다.ReferenceEquals 유형을때단, 참조유처때단할리을형단때(,▁the▁reference▁handling▁when,string클래스는 C#이 이미 값 동일성을 검정하는 방법을 알고 있는 인스턴스입니다.

  • Equals (두 개의 개별적인 에도.)int변수는 메모리의 동일한 위치에 존재하지 않으며 동일한 값을 포함할 수 있습니다.)
  • ReferenceEquals참조를 비교하고 피연산자가 메모리에서 동일한 개체를 가리키는지 여부를 반환합니다.

코드 예제:

var s1 = new StringBuilder("str");
var s2 = new StringBuilder("str");
StringBuilder sNull = null;

s1.Equals(s2); // True
object.ReferenceEquals(s1, s2); // False
s1 == s2 // True - it calls Equals within operator overload
s1 == sNull // False
object.ReferenceEquals(s1, sNull); // False
s1.Equals(sNull); // Nono!  Explode (Exception)

의 속성TreeViewItem이 유에맞정게입적다니습력었되로으형▁to로 입력됩니다.object.

그므로러로.== 확량수false다음과 같은 간단한 스니펫으로 이를 복제할 수 있습니다.

object s1 = "Hallo";

// don't use a string literal to avoid interning
string s2 = new string(new char[] { 'H', 'a', 'l', 'l', 'o' });

bool equals = s1 == s2;         // equals is false
equals = string.Equals(s1, s2); // equals is true

Jon Skeet의 답변 외에도, 저는 왜 대부분을 사용할 때== 당은실로답을얻습다니제신▁answer다얻▁the니▁get습라는 답을 얻습니다.true동일한 값을 가진 다른 문자열 인스턴스:

string a = "Hell";
string b = "Hello";
a = a + "o";
Console.WriteLine(a == b);

당신이 볼 수 있듯이.a그리고.b다른 문자열 인스턴스여야 하지만 문자열은 불변이기 때문에 런타임은 소위 문자열 인터닝을 사용하여 둘 다 허용합니다.a그리고.b메모리에서 동일한 문자열을 참조합니다.== for 는 reference를하며, 두 개의 for operator for objects는 모두 reference를 확인합니다. 그리고 두 개 모두a그리고.b인스턴스를 는 동한인스를참결조다같음습다니과과는면일스턴입니다.true둘 중 하나를 변경하면 새 문자열 인스턴스가 생성되므로 문자열 인터닝이 가능합니다.

그건 그렇고, 존 스키트의 대답은 완전하지 않습니다. 실로제로▁indeed실.x == y이라false하지만 그것은 단지 그가 물체와 물체를 기준으로 비교하기 때문입니다.당신이 쓴다면,(string)x == (string)y돌아올 것입니다.true 한 번. 문자열에 ==-오버로드되어 , 는 ==-codice_1를 불러요. --codice_1, 2, 3, 4, 4, .String.Equals

여기에는 많은 설명적인 답변이 있으므로 이미 말한 것을 반복하지 않을 것입니다.제가 추가하고 싶은 것은 제가 생각할 수 있는 모든 순열을 보여주는 다음 코드입니다.조합 수에 따라 코드가 상당히 깁니다.MSTest에 자유롭게 드롭하여 출력을 직접 확인하십시오(출력은 하단에 포함됨).

이 증거는 존 스키트의 대답을 뒷받침합니다.

코드:

[TestMethod]
public void StringEqualsMethodVsOperator()
{
    string s1 = new StringBuilder("string").ToString();
    string s2 = new StringBuilder("string").ToString();

    Debug.WriteLine("string a = \"string\";");
    Debug.WriteLine("string b = \"string\";");

    TryAllStringComparisons(s1, s2);

    s1 = null;
    s2 = null;

    Debug.WriteLine(string.Join(string.Empty, Enumerable.Repeat("-", 20)));
    Debug.WriteLine(string.Empty);
    Debug.WriteLine("string a = null;");
    Debug.WriteLine("string b = null;");

    TryAllStringComparisons(s1, s2);
}
private void TryAllStringComparisons(string s1, string s2)
{
    Debug.WriteLine(string.Empty);
    Debug.WriteLine("-- string.Equals --");
    Debug.WriteLine(string.Empty);
    Try((a, b) => string.Equals(a, b), s1, s2);
    Try((a, b) => string.Equals((object)a, b), s1, s2);
    Try((a, b) => string.Equals(a, (object)b), s1, s2);
    Try((a, b) => string.Equals((object)a, (object)b), s1, s2);

    Debug.WriteLine(string.Empty);
    Debug.WriteLine("-- object.Equals --");
    Debug.WriteLine(string.Empty);
    Try((a, b) => object.Equals(a, b), s1, s2);
    Try((a, b) => object.Equals((object)a, b), s1, s2);
    Try((a, b) => object.Equals(a, (object)b), s1, s2);
    Try((a, b) => object.Equals((object)a, (object)b), s1, s2);

    Debug.WriteLine(string.Empty);
    Debug.WriteLine("-- a.Equals(b) --");
    Debug.WriteLine(string.Empty);
    Try((a, b) => a.Equals(b), s1, s2);
    Try((a, b) => a.Equals((object)b), s1, s2);
    Try((a, b) => ((object)a).Equals(b), s1, s2);
    Try((a, b) => ((object)a).Equals((object)b), s1, s2);

    Debug.WriteLine(string.Empty);
    Debug.WriteLine("-- a == b --");
    Debug.WriteLine(string.Empty);
    Try((a, b) => a == b, s1, s2);
#pragma warning disable 252
    Try((a, b) => (object)a == b, s1, s2);
#pragma warning restore 252
#pragma warning disable 253
    Try((a, b) => a == (object)b, s1, s2);
#pragma warning restore 253
    Try((a, b) => (object)a == (object)b, s1, s2);
}
public void Try<T1, T2, T3>(Expression<Func<T1, T2, T3>> tryFunc, T1 in1, T2 in2)
{
    T3 out1;

    Try(tryFunc, e => { }, in1, in2, out out1);
}
public bool Try<T1, T2, T3>(Expression<Func<T1, T2, T3>> tryFunc, Action<Exception> catchFunc, T1 in1, T2 in2, out T3 out1)
{
    bool success = true;
    out1 = default(T3);

    try
    {
        out1 = tryFunc.Compile()(in1, in2);
        Debug.WriteLine("{0}: {1}", tryFunc.Body.ToString(), out1);
    }
    catch (Exception ex)
    {
        Debug.WriteLine("{0}: {1} - {2}", tryFunc.Body.ToString(), ex.GetType().ToString(), ex.Message);
        success = false;
        catchFunc(ex);
    }

    return success;
}

출력:

string a = "string";
string b = "string";

-- string.Equals --

Equals(a, b): True
Equals(Convert(a), b): True
Equals(a, Convert(b)): True
Equals(Convert(a), Convert(b)): True

-- object.Equals --

Equals(a, b): True
Equals(Convert(a), b): True
Equals(a, Convert(b)): True
Equals(Convert(a), Convert(b)): True

-- a.Equals(b) --

a.Equals(b): True
a.Equals(Convert(b)): True
Convert(a).Equals(b): True
Convert(a).Equals(Convert(b)): True

-- a == b --

(a == b): True
(Convert(a) == b): False
(a == Convert(b)): False
(Convert(a) == Convert(b)): False
--------------------

string a = null;
string b = null;

-- string.Equals --

Equals(a, b): True
Equals(Convert(a), b): True
Equals(a, Convert(b)): True
Equals(Convert(a), Convert(b)): True

-- object.Equals --

Equals(a, b): True
Equals(Convert(a), b): True
Equals(a, Convert(b)): True
Equals(Convert(a), Convert(b)): True

-- a.Equals(b) --

a.Equals(b): System.NullReferenceException - Object reference not set to an instance of an object.
a.Equals(Convert(b)): System.NullReferenceException - Object reference not set to an instance of an object.
Convert(a).Equals(b): System.NullReferenceException - Object reference not set to an instance of an object.
Convert(a).Equals(Convert(b)): System.NullReferenceException - Object reference not set to an instance of an object.

-- a == b --

(a == b): True
(Convert(a) == b): True
(a == Convert(b)): True
(Convert(a) == Convert(b)): True

는 것이 분명합니다.tvi.header가 아닙니다.String.== 오버연는다니산입자되드에 의해 가 걸리는 입니다.String클래스, 즉 컴파일러가 연산자의 양쪽이 모두라는 것을 알고 있을 때만 작동한다는 것을 의미합니다.String.

개체는 고유한 OBJECT_ID로 정의됩니다.A와 B가 객체이고 A == B가 참이면 객체가 동일하고 데이터와 방법이 동일하지만 다음과 같은 경우도 마찬가지입니다.

A.OBJECT_ID == B.개체_ID

A.Equals(B)가 참이면 두 물체가 동일한 상태에 있다는 것을 의미하지만, A가 B와 동일하다는 것을 의미하지는 않습니다.

문자열은 객체입니다.

== 및 동등 연산자는 반사적이고, 시메트릭이며, 전이적이므로 동등한 관계입니다(관계형 대수 용어 사용).

이것의 의미:A, B 및 C가 객체인 경우:

A == A는 항상 참이고 A는 항상 참입니다.등식(A)은 항상 참(굴절성)입니다.

A == B이면 B == A, A이면 A입니다.(B) 다음에 B와 같습니다.등호(A)(시뮬레이션)

A == B, B == C이면 A == C, A이면 A입니다.(B)와 (B)가 같습니다.A 다음에 (C)와 같습니다.등호(C)(투명도)

또한 다음과 같은 사실도 확인할 수 있습니다.

(A == B) => (A)등호(B)), 그러나 그 반대는 참이 아닙니다.

A B =>
0 0 1
0 1 1
1 0 0
1 1 1

실생활의 예:동일한 유형의 두 햄버거는 동일한 속성을 가집니다. 햄버거 클래스의 개체이며 속성은 정확히 동일하지만 서로 다른 개체입니다.만약 당신이 이 햄버거 두 개를 사서 하나를 먹으면, 다른 하나는 먹을 수 없을 것입니다.Equals와 ==의 차이: 햄버거1과 햄버거2가 있습니다.그들은 정확히 같은 상태에 있습니다 (같은 무게, 같은 온도, 같은 맛), 그래서 햄버거1.등호(햄버거2)는 참입니다.하지만 햄버거1 == 햄버거2는 거짓입니다. 왜냐하면 햄버거1의 상태가 바뀌면 햄버거2의 상태가 반드시 바뀌지는 않고 그 반대도 되기 때문입니다.

만약 당신과 친구가 동시에 당신의 햄버거와 그의 햄버거를 얻는다면, 당신은 햄버거를 두 부분으로 나누기로 결정해야 합니다. 왜냐하면 당신은.getHamburger() == friend.getHamburger()가 사실이고 만약 이런 일이 일어난다면, 당신의 햄버거도 먹을 것이기 때문입니다.

Equals와 ==에 대해 다른 뉘앙스를 쓸 수도 있지만, 배가 고파서 가야 합니다.

잘 부탁드립니다, 라호스 아르패드.

언급URL : https://stackoverflow.com/questions/3678792/are-string-equals-and-operator-really-same

반응형