Structs에서 Equals 메서드 재정의
구조체에 대한 재정의 지침을 찾았지만 찾을 수있는 것은 클래스에 대한 것뿐입니다.
처음에는 구조체가 값 형식이고 null이 될 수 없기 때문에 전달 된 개체가 null인지 확인할 필요가 없다고 생각했습니다. 하지만 이제 생각하게 되었으니, 동등 서명은
public bool Equals(object obj)
내 구조체의 사용자가 임의의 참조 유형과 비교하려고 시도하는 것을 방해하는 것은없는 것 같습니다.
두 번째 요점은 구조체의 개인 필드를 비교하기 전에 캐스팅해야하는 캐스팅에 관한 것입니다. 객체를 내 구조체의 유형으로 어떻게 캐스팅해야합니까? C #의 as
키워드는 참조 유형에만 적합합니다.
struct MyStruct
{
public override bool Equals(object obj)
{
if (!(obj is MyStruct))
return false;
MyStruct mys = (MyStruct) obj;
// compare elements here
}
}
.NET 4.5 를 사용하는 경우 설명서에 명시된대로 기본 구현을 사용할 수 있습니다 .
고유 한 유형을 정의하면 해당 유형은 기본 유형의 Equals 메서드에 의해 정의 된 기능을 상속합니다.
ValueType.Equals : 값이 같음; 직접 바이트 별 비교 또는 리플렉션을 사용한 필드 별 비교.
C # 7.0의 몇 가지 뉴스 덕분에 수락 된 답변과 동일한 작업을 수행하는 더 쉬운 방법이 있습니다.
struct MyStruct
{
public override bool Equals(object obj)
{
if (!(obj is MyStruct mys)) // type pattern here
return false;
return this.field1 == mys.field1 && this.field2 == mys.field2 // mys is already known here without explicit casting
}
}
또는 내가 가장 좋아하는-표현 신체 기능과 동일 :
struct MyStruct
{
public override bool Equals(object obj) =>
obj is MyStruct mys
&& mys.field1 == this.field1
&& mys.field2 == this.field2;
}
경우 누구의가 null 허용 개체의 구조체 권투의 성능 저하에 대해 궁금에서 (에서 double 형 체크하지 않도록 is
하고 캐스트)가 있다 무시할 수없는 오버 헤드.
tl; dr : is
이 시나리오에서 사용 및 캐스팅합니다.
struct Foo : IEquatable<Foo>
{
public int a, b;
public Foo(int a, int b)
{
this.a = a;
this.b = b;
}
public override bool Equals(object obj)
{
#if BOXING
var obj_ = obj as Foo?;
return obj_ != null && Equals(obj_.Value);
#elif DOUBLECHECK
return obj is Foo && Equals((Foo)obj);
#elif MAGIC
?
#endif
}
public bool Equals(Foo other)
{
return a == other.a && b == other.b;
}
}
class Program
{
static void Main(string[] args)
{
RunBenchmark(new Foo(42, 43), new Foo(42, 43));
RunBenchmark(new Foo(42, 43), new Foo(43, 44));
}
static void RunBenchmark(object x, object y)
{
var sw = Stopwatch.StartNew();
for (var i = 0; i < 100000000; i++) x.Equals(y);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
}
결과 :
BOXING
EQ 8012 7973 7981 8000
NEQ 7929 7715 7906 7888
DOUBLECHECK
EQ 3654 3650 3638 3605
NEQ 3310 3301 3319 3297
Warning: This test might be flawed in many ways, though I did verify that the benchmark code itself wasn't optimized in an odd fashion.
Looking at the IL, the double-check method compiles a little cleaner.
Boxing IL:
.method public hidebysig virtual
instance bool Equals (
object obj
) cil managed
{
// Method begins at RVA 0x2060
// Code size 37 (0x25)
.maxstack 2
.locals init (
[0] valuetype [mscorlib]System.Nullable`1<valuetype StructIEqualsImpl.Foo> obj_
)
IL_0000: ldarg.1
IL_0001: isinst valuetype [mscorlib]System.Nullable`1<valuetype StructIEqualsImpl.Foo>
IL_0006: unbox.any valuetype [mscorlib]System.Nullable`1<valuetype StructIEqualsImpl.Foo>
IL_000b: stloc.0
IL_000c: ldloca.s obj_
IL_000e: call instance bool valuetype [mscorlib]System.Nullable`1<valuetype StructIEqualsImpl.Foo>::get_HasValue()
IL_0013: brfalse.s IL_0023
IL_0015: ldarg.0
IL_0016: ldloca.s obj_
IL_0018: call instance !0 valuetype [mscorlib]System.Nullable`1<valuetype StructIEqualsImpl.Foo>::get_Value()
IL_001d: call instance bool StructIEqualsImpl.Foo::Equals(valuetype StructIEqualsImpl.Foo)
IL_0022: ret
IL_0023: ldc.i4.0
IL_0024: ret
} // end of method Foo::Equals
Double-check IL:
.method public hidebysig virtual
instance bool Equals (
object obj
) cil managed
{
// Method begins at RVA 0x2060
// Code size 23 (0x17)
.maxstack 8
IL_0000: ldarg.1
IL_0001: isinst StructIEqualsImpl.Foo
IL_0006: brfalse.s IL_0015
IL_0008: ldarg.0
IL_0009: ldarg.1
IL_000a: unbox.any StructIEqualsImpl.Foo
IL_000f: call instance bool StructIEqualsImpl.Foo::Equals(valuetype StructIEqualsImpl.Foo)
IL_0014: ret
IL_0015: ldc.i4.0
IL_0016: ret
} // end of method Foo::Equals
Props to Roman Reiner for spotting a mistake that really wasn't making me look good.
Use the is
operator:
public bool Equals(object obj)
{
if (obj is MyStruct)
{
var o = (MyStruct)obj;
...
}
}
Adding to the existing answers.
You can still have nullable values if you append a ? after the struct name (this works for every value object)
int?
Casting is done also by calling (MyStructName)variableName
ReferenceURL : https://stackoverflow.com/questions/2542693/overriding-equals-method-in-structs
'UFO ET IT' 카테고리의 다른 글
C ++ / CLI : 왜 사용해야합니까? (0) | 2021.01.14 |
---|---|
MySQL 다중 왼쪽 조인 (0) | 2021.01.14 |
메시지 다이제스트, 메시지 인증 코드 및 HMAC의 차이점은 무엇입니까? (0) | 2021.01.14 |
"git describe"는 태그를 무시합니다. (0) | 2021.01.14 |
CSS 요소가 다음과 같이 작동하도록 할 수 있습니까? (0) | 2021.01.14 |