Section 6.4: IEqualityComparer 에서의 Equals 와 GetHashCode

아래와 같이 주어진 Person 타입이 있다고 가정할 때:

public class Person { public string Name { get; set; } public int Age { get; set; } public string Clothes { get; set; } } List < Person > persons = new List < Person > { new Person { Name = "Jon", Age = 20, Clothes = "some clothes" }, new Person { Name = "Dave", Age = 20, Clothes = "some other clothes" }, new Person { Name = "Jon", Age = 20, Clothes = "" } }; var distinctPersons = persons.Distinct().ToList();// distinctPersons 는 Count = 3 값을 가지게 된다

그러나 EqualsGetHashCodeIEqualityComparator 안에 구현하게 되면 :

public class PersonComparator: IEqualityComparer < Person > { public bool Equals(Person x, Person y) { return x.Name == y.Name && x.Age == y.Age; // 같은 사람인지 비교에 있어 옷은 중요하지 않다 } public int GetHashCode(Person obj) { return obj.Name.GetHashCode() * obj.Age; } } var distinctPersons = persons.Distinct(new PersonComparator()).ToList(); // distinctPersons 는 Count = 2 값을 가지게 된다

후자 query 에 대해서는, 두 사람 객체에 대하여 Equals 가 true 를 반환하고 GetHashCode 가 동일한 해시코드를 반환하는 경우에 같다고 간주되고 있음에 유의한다.

역주: 섹션 6.3 과의 차이점은, 이전 예제에서는 EqualsGetHashCode 가 객체 내부에 재정의 되었고, 이 예제에서는 비교 코드를 객체 외부에 따로 정의하였다는 점입니다.

본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 6.3: 사용자 정의 타입에 대해 Equals 와 GetHashCode 재정의하기

다음과 같은 Person 클래스가 있다고 할 때:

public class Person {} public string Name { get; set; } public int Age { get; set; } public string Clothes { get; set; } var person1 = new Person { Name = "Jon", Age = 20, Clothes = "some clothes" }; var person2 = new Person { Name = "Jon", Age = 20, Clothes = "some other clothes" }; bool result = person1.Equals(person2); // reference 타입의 Equals 이기 때문에 false 를 반환한다

EqualsGetHashCode 를 다음과 같이 정의할 수 있다:

public class Person { public string Name { get; set; } public int Age { get; set; } public string Clothes { get; set; } public override bool Equals(object obj) { var person = obj as Person; if (person == null) return false; return Name == person.Name && Age == person.Age; // 같은 사람인지 비교에 있어 옷은 중요하지 않다 } public override int GetHashCode() { return Name.GetHashCode() * Age; } } var person1 = new Person { Name = "Jon", Age = 20, Clothes = "some clothes" }; var person2 = new Person { Name = "Jon", Age = 20, Clothes = "some other clothes" }; bool result = person1.Equals(person2); // result 는 true 가 된다

또한 LINQ 를 사용하여 persons 에 대한 다른 query 를 만드는 경우 Equals 와 GetHashCode 가 모두 사용된다:

var persons = new List < Person > { new Person { Name = "Jon", Age = 20, Clothes = "some clothes" }, new Person { Name = "Dave", Age = 20, Clothes = "some other clothes" }, new Person { Name = "Jon", Age = 20, Clothes = "" } }; var distinctPersons = persons.Distinct().ToList(); // distinctPersons 는 Count = 2 의 값을 가지게 된다
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 6.2: Equals 의 기본 동작

EqualsObject 클래스 자체에 아래와 같이 정의가 되어있다.

public virtual bool Equals(Object obj);

Equals 는 다음과 같은 기본 동작을 가지고 있다:

  • 만약 instance 가 reference 타입이라면, Equals 는 두 reference 가 동일할 때 true 를 반환한다.
  • 만약 instance 가 값 (value) 타입이라면, Equals 는 타입과 값 자체가 동일할 때 true 를 반환한다.
  • string 은 특별한 경우로, 값 타입처럼 동작한다.
namespace ConsoleApplication { public class Program { public static void Main(string[] args) { //areFooClassEqual: False Foo fooClass1 = new Foo("42"); Foo fooClass2 = new Foo("42"); bool areFooClassEqual = fooClass1.Equals(fooClass2); Console.WriteLine("fooClass1 and fooClass2 are equal: {0}", areFooClassEqual); //False //areFooIntEqual: True int fooInt1 = 42; int fooInt2 = 42; bool areFooIntEqual = fooInt1.Equals(fooInt2); Console.WriteLine("fooInt1 and fooInt2 are equal: {0}", areFooIntEqual); //areFooStringEqual: True string fooString1 = "42"; string fooString2 = "42"; bool areFooStringEqual = fooString1.Equals(fooString2); Console.WriteLine("fooString1 and fooString2 are equal: {0}", areFooStringEqual); } } public class Foo { public string Bar { get; } public Foo(string bar) { Bar = bar; } } }
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 6.1: 바람직한 GetHashCode 재정의하기

GetHashCodeDictionary<>HashTable 사용에 있어 성능에 지대한 영향을 미치게 된다.

바람직한 GetHashCode 메소드란:

  • 균일한 분포 (distribution) 를 가져야 한다.
    • 임의의 instance 에 대해, 값으로 반환될 수 있는 확률은 모든 integer 값들이 거의 동일하게 가져야 한다.
    • 만약 각각의 instance 들에 대해 동일한 integer 를 반환하게되어 있다면 (예: 언제나 상수 '999' 만을 반환), 성능 저하가 심각하게 일어날 것이다.
  • 빠르게 동작해야 한다.
    • 이 메소드는 (느린 동작을 특징으로 갖는) 암호화 hash 값을 생성하기 위한 것이 아니다.
    • hash 함수가 느려질수록, 사용자의 dictionary 역시 마찬가지로 느려질 것이다.
  • Equals 가 true 로 평가 (evaluate) 되는 두개의 instance 에 대해서는 동일한 HashCode 를 반환해야 한다.
    • 그렇지 않은 경우 (예: GetHashCode 가 난수를 반환한다거나), ListDictionary 혹은 그 비슷한 것들에서 요소 검색에 실패할 수 있다.

GetHashCode 를 구현하는 좋은 방법 중 하나는 소수 하나를 시작값으로 하여, 각 field 들의 hashcode 를 다른 소수와 곱하여 더해 나가는 것이다:

public override int GetHashCode() { unchecked // Overflow 가 발생한다해도 wrap 시키면 되므로 문제가 없다 { int hash = 3049; // 시작 값 (소수) // 이 위치에 적절한 null 확인 등의 코드가 필요할 것이다 hash = hash * 5039 + field1.GetHashCode(); hash = hash * 883 + field2.GetHashCode(); hash = hash * 9719 + field3.GetHashCode(); return hash; } }

Equals 메소드에서 사용되는 field 들만 hash 값 연산에 사용되어야 함에 주의하자.

만약 동일한 타입을 Dictionary / HashTable 들에 대하여 각각 다른 방법으로 다루어야 하는 필요가 있는 경우에는, IEqualityComparer 를 사용할 수 있다.

본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

Section 5.1: C# 에서의 동일성 (equally) 종류와 동일 연산자

C# 에서는, 동일함을 판별하는 두가지 종류가 있다: reference 동일성과 값 (value) 동일성이 바로 그것이다. 값 동일성이 흔히 이해하는 동일함에 가깝다: 이는 두개의 객체 (object) 가 같은 값을 가지고 있음을 의미한다. 예를 들어, 2 라는 값을 갖고있는 두개의 integer 는 값 동일성을 갖고있다. Reference 동일성은 비교를 수행해야하는 객체가 두개나 존재하지 않음을 의미한다. 대신, 하나의 객체를 가리키는 두개의 객체 참조 (object reference) 가 존재할 뿐이다.

object a = new object(); object b = a; System.Object.ReferenceEquals(a, b); // true 를 반환한다

미리 정의된 값 타입 (predefinened value types) 에 대해서는, 피연산자들의 값이 동일할 때 동일 연산자 (==) 가 true 를 반환하며, 그렇지 않을 때 false 를 반환한다. string 을 제외한 reference 타입에 대해서는, == 는 두 피연산자가 같은 객체를 참조하고 있을 때 true 를 반환한다. string 타입에 대해서는, == 는 두 문자열의 값을 비교하게 된다.

// 수 (numeric) 동일성 : True Console.WriteLine((2 + 2) == 4); // Reference 동일성 : 동일한 값이 boxing 된 // 다른 object 들: False. object s = 1; object t = 1; Console.WriteLine(s == t); // 문자열을 몇 개 정의한다: string a = "hello"; string b = String.Copy(a); string c = "hello"; // 상수 (constant) 와 instance 의 문자열 값 비교 : True Console.WriteLine(a == b); // 문자열 reference 비교 // a 는 상수이나 b 는 instance 이다: False. Console.WriteLine((object)a == (object)b); // 문자열 reference 비교 // 두 상수가 모두 같은 값을 가지고 있으므로, // 문자열 인턴 지정 (interning) 은 같은 reference 를 가리킨다 : True. Console.WriteLine((object)a == (object)c);
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

'번역 > C# Notes for Professionals' 카테고리의 다른 글

6.2: Equals 의 기본 동작  (0) 2020.11.23
6.1: 바람직한 GetHashCode 재정의하기  (0) 2020.11.20
4.3: If-Else If-Else 문  (0) 2020.11.17
4.2: If 문의 조건식  (0) 2020.11.17
4.1: If-Else 문  (0) 2020.11.16

Section 4.3: If-Else If-Else 문

If-Else 문 예제에 이어서, 이번에는 Else If 문에 대해 알아보도록 한다. Else If 문은 If-Else If-Else 구조에서 If 문 바로 뒤에 따르게 되며, If 문과 본질적으로 유사한 문법을 가지고 있다. 이는 기본적인 If-Else 문이 제공하는 것보다 더 많은 분기를 추가하고자 할 때 사용된다.

If-Else 문 예제에서, 점수의 최대값은 100 이라고 가정하였으나 실제적으로 이를 확인하는 부분은 존재하지 않았다. 이를 해결하기 위하여, If-Else 문을 아래와 같이 수정할 수 있다:

static void PrintPassOrFail(int score) { if (score > 100) // 만약 점수가 100 보다 큰 경우 { Console.WriteLine("Error: score is greater than 100!"); } else if (score < 0) // 혹은 점수가 0 보다 작은 경우 { Console.WriteLine("Error: score is less than 0!"); } else if (score >= 50) // 혹은 점수가 50 보다 크거나 같은 경우 { Console.WriteLine("Pass!"); } else // 만약 위 모든 조건에 부합하지 않는다면, 점수는 0 과 49 사이일 것이다 { Console.WriteLine("Fail!"); } }

위의 모든 구문은 가장 위에서부터 아래 방향으로 부합하는 조건을 찾을때까지 실행될 것이다. 기존 메소드에 점수가 범위를 벗어나는 경우를 처리하기 위해 두개의 새로운 분기 경로를 추가하였다.

예를 들어, 이 메소드가 PrintPassOFail(110); 와 같이 불린 경우, 해당 메소드는 콘솔에 "Error: score is greater than 100!" 를 출력하게 될 것이다. 그리고 이 메소드가 PrintPassOrFail(-20); 와 같이 불린 경우, 해당 메소드는 콘솔에 "Error: score is less than 0!" 을 출력하게 될 것이다.

본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형
CSharpNotes.4-2.md

Section 4.2: If 문의 조건식

아래와 같은 구문의 경우,

if (conditionA && conditionB && conditionC) //...

아래 구문과 완전히 동등 (equivalent) 하다.

bool conditions = conditionA && conditionB && conditionC; if (conditions) // ...

달리 말하면, if 문 안의 조건식은 일반적인 Boolean 표현식에 해당한다.

흔히들 조건 구문을 작성할 때 truefalse 와 직접 비교하도록 작성하기가 쉬운데,

if (conditionA == true && conditionB == false && conditionC == true) // ...

이는 아래와 같이 간략하게 작성할 수 있다.

if (conditionA && !conditionB && conditionC)
본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

'번역 > C# Notes for Professionals' 카테고리의 다른 글

5.1: C# 에서의 동일성 (equally) 종류와 동일 연산자  (0) 2020.11.19
4.3: If-Else If-Else 문  (0) 2020.11.17
4.1: If-Else 문  (0) 2020.11.16
3.21: 클래스 멤버 연산자  (0) 2020.11.13
3.20: nameof 연산자  (0) 2020.11.13

Section 4.1: If-Else 문

일반적으로 프로그래밍시에는 각각 다른 입력이나 놓여진 상황에 따라 프로그램이 어떻게 다르게 동작하여야 하는지에 대해 결정하고 분기를 수행하여야 하는 경우가 종종 발생한다. C# 프로그래밍 언어에서는 (이 부분에 대해서 거의 대부분의 다른 프로그래밍 언어와 마찬가지로), 이러한 분기를 사용자의 프로그램 내에서 가장 간단하고도 때에 따라 가장 유용하게 생성할 수 있는 방법이 바로 If-Else 문을 이용하는 것이다.

숫자 100 까지의 점수를 나타내는 int 파라미터를 받아 합격 혹은 불합격을 출력해주는 메소드 (함수라고도 알려진) 를 작성하는 경우를 가정해보자.

static void PrintPassOrFail(int score) { if (score >= 50) // 점수가 50 이상인 경우 { Console.WriteLine("Pass!"); } else // 점수가 50 미만인 경우 { Console.WriteLine("Fail!"); } }

이 메소드를 살펴보면, 다음 (score >= 50) 과 같은 코드가 if 문 안에 존재함을 발견할 수 있을 것이다. 이는 boolean 조건으로써, 해당 조건이 참으로 평가 (evaluate) 되면, if { } 사이에 있는 코드가 실행되게 된다.

예를 들어, 만약 이 메소드가 다음과 같이 불렸다고 하면: PrintPassOrFail(60);, 파라미터인 값 60 이 50 보다 크거나 같으므로, 해당 메소드는 콘솔에 Pass! 를 출력하게 될 것이다. 그러나, 만약 이 메소드가 다음과 같이 불렸다고 하면: PrintPassOrFail(30);, 해당 메소드는 Fail! 을 출력하게 될 것이다. 이는 파라미터인 값 30 이 50 보다 크거나 같지 않기 때문으로, if { } 대신 else { } 사이에 있는 코드가 실행되게 될 것이다.

이 예제에서 점수의 최대값이 100 이라고 가정하였지만, 그 조건에 대해 특별히 처리를 하지는 않았다. 점수가 100 을 넘어가거나 0 아래의 값이 아니도록 처리하기 위해서는, If-Else If-Else 문예제를 참고하라.

본 문서는 C# Notes for Professionals (라이센스:CC-BY-SA) 를 한글로 번역한 문서입니다. 번역상 오류가 있을 수 있으므로 정확한 내용은 원본 문서를 참고하세요.

[출처] https://books.goalkicker.com/CSharpBook/

반응형

'번역 > C# Notes for Professionals' 카테고리의 다른 글

4.3: If-Else If-Else 문  (0) 2020.11.17
4.2: If 문의 조건식  (0) 2020.11.17
3.21: 클래스 멤버 연산자  (0) 2020.11.13
3.20: nameof 연산자  (0) 2020.11.13
3.19: 대입 이항 연산자  (0) 2020.11.11

+ Recent posts