我有一个自定义类,同时实现了 ==
和 implicit
对于布尔运算符。
这是处理所有可能的if == /!=语句并获得预期结果的正确方法吗?
喜欢这个:
public class Foo
{
public bool Result { get; set; }
public static bool operator ==(bool @bool, Foo foo)
{
return Equals(foo, @bool);
}
public static bool operator !=(bool @bool, Foo foo)
{
return NotEquals(foo, @bool);
}
public static bool operator ==(Foo foo, bool @bool)
{
return Equals(foo, @bool);
}
public static bool operator !=(Foo foo, bool @bool)
{
return NotEquals(foo, @bool);
}
public static bool operator ==(Foo foo, Foo fooB)
{
return Equals(foo, fooB);
}
public static bool operator !=(Foo foo, Foo fooB)
{
return NotEquals(foo, fooB);
}
public static implicit operator bool(Foo foo)
{
try { return foo.Result; }
catch { return false; }
}
private static bool Equals(Foo foo, Foo fooB)
{
if (object.Equals(foo, null))
{
if (object.Equals(fooB, null))
return true;
return false;
}
if (object.Equals(fooB, null))
return false;
return foo.Result == fooB.Result;
}
private static bool NotEquals(Foo foo, Foo fooB)
{
if (object.Equals(foo, null))
{
if (object.Equals(fooB, null))
return false;
return true;
}
if (object.Equals(fooB, null))
return true;
return fooB.Result != foo.Result;
}
private static bool Equals(Foo foo, bool @bool)
{
if (object.Equals(foo, null))
return true;
return @bool == foo.Result;
}
private static bool NotEquals(Foo foo, bool @bool)
{
if (object.Equals(foo, null))
return false;
return @bool != foo.Result;
}
}
我特别想知道它似乎真的需要实现重载
if (new Foo() != true)
和
if (true != new Foo())
我觉得你写的代码太多了:-)
以下就足够了:
public class Foo
{
public bool Result { get; set; }
public static implicit operator bool(Foo foo)
{
return !object.ReferenceEquals(foo, null) && foo.Result;
}
}
然后编译器将知道如何隐式转换类型的变量 Foo
成 bool
。 (和 null
将被转换为 false
)。
所以,当你写:
new Foo() == false
编译器将使用隐式类型转换器来获取 bool
来自的价值 Foo
然后使用标准的相等运算符 bool
。
如果我们查看编译器为该表达式生成的IL,我们会发现:
newobj instance void FooBool.Foo::.ctor() // new Foo()
call bool FooBool.Foo::op_Implicit(class FooBool.Foo) // implicit operator (Foo => bool)
ldc.i4.0 // false
ceq // equality operator (bool)
这是一个测试:
static void Main(string[] args)
{
AssertTrue(new Foo() == false);
AssertTrue(false == new Foo());
AssertFalse(new Foo() != false);
AssertFalse(false != new Foo());
AssertTrue(new Foo { Result = true } == true);
AssertTrue(true == new Foo { Result = true });
AssertFalse(new Foo { Result = true } != true);
AssertFalse(true != new Foo { Result = true });
}
static void AssertTrue(bool value)
{
Console.WriteLine(value ? "ok" : "not ok");
}
static void AssertFalse(bool value)
{
Console.WriteLine(value ? "not ok" : "ok");
}
它打印 ok
每次测试。因此,如果我理解正确,这个简化的代码应该满足您的需求。
UPDATE
允许相等运算符用于实例 Foo
(可能为空):
public static bool operator ==(Foo a, Foo b)
{
if (object.ReferenceEquals(a, b))
{
return true;
}
else if (object.ReferenceEquals(a, null))
{
return !b.Result;
}
else if (object.ReferenceEquals(b, null))
{
return !a.Result;
}
else
{
return a.Result == b.Result;
}
}
您还应该实现不等式运算符:
public static bool operator !=(Foo a, Foo b)
{
return !(a == b);
}
并覆盖 GetHashCode
+ Equals
public override int GetHashCode()
{
return this.Result ? 1 : 0;
}
public override bool Equals(object obj)
{
if (object.ReferenceEquals(obj, null))
{
return !this.Result;
}
Type t = obj.GetType();
if (t == typeof(Foo))
{
return this.Result == ((Foo)obj).Result;
}
else if (t == typeof(bool))
{
return this.Result == (bool)obj;
}
else
{
return false;
}
}
我认为您明确涵盖了代码中的所有基础;如果需要,你必须考虑操作员的参数顺序,如果你想要你的 Equals
你所做的参数排序调用的函数是正确的。
然而,在比较的情况下,它看起来有点矫枉过正 Foo
至 bool
因为你可以简单地依赖隐式转换。这将允许您删除两种类型之间的所有运算符以及 Equals
和 NotEquals
方法。
更重要的是,它可以避免代码中关于将null Foo转换为布尔值的一些不一致。当你传递一个空Foo到 Equals
它将返回的方法 true
而在隐式转换中,将返回null Foo false
:
true == (Foo)null; //true
true == Convert.ToBoolean((Foo)null); //false
最后,这是我如何编写Foo类,我认为这已经足够了:
public class Foo
{
public bool Result { get; set; }
public static bool operator ==(Foo foo, Foo fooB)
{
return Equals(foo, fooB);
}
public static bool operator !=(Foo foo, Foo fooB)
{
return NotEquals(foo, fooB);
}
public static implicit operator bool(Foo foo)
{
return foo == null ? false : foo.Result;
}
private static bool Equals(Foo foo, Foo fooB)
{
if (object.Equals(foo, null))
{
return object.Equals(fooB, null);
}
if (object.Equals(fooB, null))
return false;
return foo.Result == fooB.Result;
}
private static bool NotEquals(Foo foo, Foo fooB)
{
return !Equals(foo, fooB);
}
}