MSDN==
운영자 의 문서에 따르면 ,
미리 정의 된 값 형식의 경우 항등 연산자 (==)는 피연산자의 값이 같으면 true를 반환하고 그렇지 않으면 false를 반환합니다. string 이외의 참조 유형의 경우 ==는 두 피연산자가 동일한 객체를 참조하면 true를 반환합니다. 문자열 유형의 경우 ==는 문자열 값을 비교합니다. 사용자 정의 값 유형은 == 연산자를 오버로드 할 수 있습니다 (연산자 참조). 기본적으로 ==는 미리 정의 된 참조 유형과 사용자 정의 참조 유형 모두에 대해 위에서 설명한대로 작동 하지만
사용자 정의 참조 유형도 가능합니다.
그렇다면 왜이 코드 스 니펫이 컴파일에 실패합니까?
bool Compare<T>(T x, T y) { return x == y; }
‘T’및 ‘T’유형의 피연산자에 연산자 ‘==’를 적용 할 수 없다는 오류가 발생 합니다. ==
연산자가 모든 유형에 대해 사전 정의되어 있다는 것을 이해하는 한 왜 궁금 합니다.
편집 : 감사합니다. 처음에는 그 진술이 참조 유형에 관한 것임을 알지 못했습니다. 나는 또한 그 비트 단위 비교가 지금 알고있는 모든 값 유형, 제공됩니다 생각 하지 올바른.
그러나 참조 유형을 사용하는 경우 ==
연산자가 사전 정의 된 참조 비교를 사용합니까, 또는 유형이 정의 된 경우 오버로드 된 연산자 버전을 사용합니까?
편집 2 : 시행 착오를 통해 ==
연산자가 무제한 제네릭 형식을 사용할 때 사전 정의 된 참조 비교를 사용 한다는 것을 알았습니다 . 실제로 컴파일러는 제한된 유형 인수에 대해 가장 좋은 방법을 사용하지만 더 이상 보지 않습니다. 예를 들어, 아래 코드 는 호출 된 true
경우에도 항상 인쇄 됩니다 Test.test<B>(new B(), new B())
.
class A { public static bool operator==(A x, A y) { return true; } }
class B : A { public static bool operator==(B x, B y) { return false; } }
class Test { void test<T>(T a, T b) where T : A { Console.WriteLine(a == b); } }
답변
“… 기본적으로 ==는 사전 정의 된 참조 유형과 사용자 정의 된 참조 유형 모두에 대해 위에서 설명한대로 작동합니다.”
타입 T는 반드시 레퍼런스 타입 일 필요는 없으므로 컴파일러는 그러한 가정을 할 수 없습니다.
그러나 더 명확하기 때문에 컴파일됩니다.
bool Compare<T>(T x, T y) where T : class
{
return x == y;
}
“하지만 참조 형식을 사용하는 경우 == 연산자가 미리 정의 된 참조 비교를 사용합니까 아니면 형식이 정의 된 경우 오버로드 된 연산자 버전을 사용합니까?”라는 추가 질문을 따릅니다.
Generics의 ==는 오버로드 된 버전을 사용한다고 생각했지만 다음 테스트에서는 그렇지 않습니다. 흥미 롭습니다 … 이유를 알고 싶습니다! 누군가 알고 있다면 공유하십시오.
namespace TestProject
{
class Program
{
static void Main(string[] args)
{
Test a = new Test();
Test b = new Test();
Console.WriteLine("Inline:");
bool x = a == b;
Console.WriteLine("Generic:");
Compare<Test>(a, b);
}
static bool Compare<T>(T x, T y) where T : class
{
return x == y;
}
}
class Test
{
public static bool operator ==(Test a, Test b)
{
Console.WriteLine("Overloaded == called");
return a.Equals(b);
}
public static bool operator !=(Test a, Test b)
{
Console.WriteLine("Overloaded != called");
return a.Equals(b);
}
}
}
산출
인라인 : 과부하 == 호출
일반적인:
계속하려면 아무 키나 누르십시오. . .
후속 2
비교 방법을 다음과 같이 바꾸는 것을 지적하고 싶습니다.
static bool Compare<T>(T x, T y) where T : Test
{
return x == y;
}
오버로드 된 == 연산자가 호출됩니다. 형식을 지정하지 않으면 ( where로 ) 컴파일러가 오버로드 된 연산자를 사용해야한다고 추론 할 수는 없지만 형식을 지정하지 않아도 결정을 내리기에 충분한 정보가 있다고 생각합니다.
답변
다른 사람들이 말했듯이 T가 참조 유형으로 제한 된 경우에만 작동합니다. 제약 조건이 없으면 null과 비교할 수 있지만 null 만 가능하며 null이 아닌 값 형식의 경우 해당 비교는 항상 false입니다.
Equals를 호출하는 대신 IComparer<T>
– 를 사용하는 것이 좋습니다. 더 이상 정보가 없으면 EqualityComparer<T>.Default
좋은 선택입니다.
public bool Compare<T>(T x, T y)
{
return EqualityComparer<T>.Default.Equals(x, y);
}
다른 것 외에도, 이것은 권투 / 캐스팅을 피합니다.
답변
일반적으로 EqualityComparer<T>.Default.Equals
구현 IEquatable<T>
또는 합리적인 Equals
구현 이있는 모든 작업을 수행해야합니다 .
그러나, 경우 ==
와 Equals
어떤 이유로 다르게 구현되어, 다음에 내 작품을 일반 사업자 유용합니다; 그것은 (다른 것들 중에서) 연산자 버전을 지원합니다 :
- 같음 (T 값 1, T 값 2)
- 같지 않음 (T value1, T value2)
- 그레이터 탄 (T value1, T value2)
- LessThan (T 값 1, T 값 2)
- GreaterThanOrEqual (T 값 1, T 값 2)
- LessThanOrEqual (T 값 1, T 값 2)
답변
하나의 답변이 아닌 많은 답변이 왜 그 이유를 설명합니까? (Giovanni가 명시 적으로 요청한) …
.NET 제네릭은 C ++ 템플릿처럼 작동하지 않습니다. C ++ 템플릿에서는 실제 템플릿 매개 변수를 알고 난 후에 과부하 해결이 발생합니다.
.NET 제네릭 (C # 포함)에서 실제 제네릭 매개 변수를 몰라도 과부하 해결이 발생합니다. 컴파일러가 호출 할 함수를 선택하기 위해 사용할 수있는 유일한 정보는 일반 매개 변수의 유형 제한 조건에서 온 것입니다.
답변
컴파일은 T가 구조체 (값 유형)가 될 수 없다는 것을 알 수 없습니다. 그래서 당신은 그것이 내가 생각하는 참조 유형 일 수 있다고 말해야합니다.
bool Compare<T>(T x, T y) where T : class { return x == y; }
T가 값 유형일 수있는 경우 x == y
유형에 연산자 ==가 정의되어 있지 않은 경우에 잘못 형성 될 수 있기 때문 입니다. 더 명백한 이것에 대해서도 마찬가지입니다.
void CallFoo<T>(T x) { x.foo(); }
함수 foo가없는 T 타입을 전달할 수 있기 때문에 실패합니다. C #을 사용하면 가능한 모든 유형에 항상 foo 함수가 있어야합니다. 이것은 where 절에 의해 수행됩니다.
답변
클래스 제약이없는 것으로 보입니다.
bool Compare<T> (T x, T y) where T: class
{
return x == y;
}
연산자 에서 class
제약 Equals
을 ==
받는 Object.Equals
동안 구조체 로부터 상속받는 반면 구조체의 구조체는 재정의 한다는 사실을 알아야합니다 ValueType.Equals
.
참고 :
bool Compare<T> (T x, T y) where T: struct
{
return x == y;
}
또한 동일한 컴파일러 오류가 발생합니다.
아직 나는 왜 값 유형 평등 연산자 비교가 컴파일러에 의해 거부되는지 이해하지 못합니다. 나는 이것이 사실이라는 것을 알고있다.
bool Compare<T> (T x, T y)
{
return x.Equals(y);
}
답변
내 경우에는 평등 연산자를 단위 테스트하고 싶었습니다. 제네릭 형식을 명시 적으로 설정하지 않고 항등 연산자에서 코드를 호출해야했습니다. 에 대한 조언은 호출 된 메소드 EqualityComparer
로 도움이되지 않았지만 평등 연산자는 아닙니다.EqualityComparer
Equals
다음은을 빌드하여 일반 유형으로 작업하는 방법 LINQ
입니다. 올바른 연산자 ==
와 !=
연산자 를 호출합니다 .
/// <summary>
/// Gets the result of "a == b"
/// </summary>
public bool GetEqualityOperatorResult<T>(T a, T b)
{
// declare the parameters
var paramA = Expression.Parameter(typeof(T), nameof(a));
var paramB = Expression.Parameter(typeof(T), nameof(b));
// get equality expression for the parameters
var body = Expression.Equal(paramA, paramB);
// compile it
var invokeEqualityOperator = Expression.Lambda<Func<T, T, bool>>(body, paramA, paramB).Compile();
// call it
return invokeEqualityOperator(a, b);
}
/// <summary>
/// Gets the result of "a =! b"
/// </summary>
public bool GetInequalityOperatorResult<T>(T a, T b)
{
// declare the parameters
var paramA = Expression.Parameter(typeof(T), nameof(a));
var paramB = Expression.Parameter(typeof(T), nameof(b));
// get equality expression for the parameters
var body = Expression.NotEqual(paramA, paramB);
// compile it
var invokeInequalityOperator = Expression.Lambda<Func<T, T, bool>>(body, paramA, paramB).Compile();
// call it
return invokeInequalityOperator(a, b);
}