dev*_*ium 56 c# struct overriding equals
我已经找到了结构的最重要的指导方针,但我能找到的只是课程.
起初我以为我不必检查传递的对象是否为null,因为结构是值类型而不能为null.但是现在我开始想起它,就像平等签名一样
public bool Equals(object obj)
Run Code Online (Sandbox Code Playgroud)
似乎没有什么能阻止我的struct的用户尝试将它与任意引用类型进行比较.
我的第二点涉及在我比较我的结构中的私有字段之前我想(我想)必须做的转换.我该如何将对象强制转换为struct的类型?C#的as关键字似乎只适用于引用类型.
Jam*_*ran 75
struct MyStruct
{
public override bool Equals(object obj)
{
if (!(obj is MyStruct))
return false;
MyStruct mys = (MyStruct) obj;
// compare elements here
}
}
Run Code Online (Sandbox Code Playgroud)
ens*_*tis 12
感谢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
}
}
Run Code Online (Sandbox Code Playgroud)
或者我最喜欢的 - 与表达身体功能相同:
struct MyStruct
{
public override bool Equals(object obj) =>
obj is MyStruct mys
&& mys.field1 == this.field1
&& mys.field2 == this.field2;
}
Run Code Online (Sandbox Code Playgroud)
如果任何人的想知道在一个可空对象拳击结构(避免双重类型检查的性能损失is和演员),还有是一个不可忽略的开销.
tl; dr:is在这种情况下使用&cast.
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);
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
BOXING
EQ 8012 7973 7981 8000
NEQ 7929 7715 7906 7888
DOUBLECHECK
EQ 3654 3650 3638 3605
NEQ 3310 3301 3319 3297
Run Code Online (Sandbox Code Playgroud)
警告:此测试可能在许多方面存在缺陷,但我确实验证了基准代码本身并未以奇怪的方式进行优化.
看看IL,双重检查方法编译得更清洁一点.
拳击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
Run Code Online (Sandbox Code Playgroud)
仔细检查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
Run Code Online (Sandbox Code Playgroud)
向罗曼·雷纳(Roman Reiner)发布道具,发现一个真正让我看起来并不好的错误.
使用is运营商:
public bool Equals(object obj)
{
if (obj is MyStruct)
{
var o = (MyStruct)obj;
...
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
27048 次 |
| 最近记录: |