我一直在寻找实际工作代码,其中重载的false
运算符实际上已被执行。
This question (What's the false operator in C# good for?)有点相同,但接受的答案会链接到返回404错误的网址。我还查看了How does operator overloading of true and false work?和其他一些问题。
我在几乎所有答案中都发现,false
仅在您使用短路时执行x && y
。这被评估为T.false(x) ? x : T.&(x, y)
。
好的,所以我有以下代码。 struct
包含int
,如果int大于零,则认为自己为真。:
public struct MyStruct {
private int _i;
public MyStruct(int i) {
_i = i;
}
public static bool operator true(MyStruct ms) {
return ms._i > 0;
}
public static bool operator false(MyStruct ms) {
return ms._i <= 0;
}
public override string ToString() {
return this._i.ToString();
}
}
现在我希望以下程序能够执行并使用重载的false
运算符。
class Program {
private static void Main() {
MyStruct b1 = new MyStruct(1); // to be considered true
MyStruct b2 = new MyStruct(-1); // to be considered false
Console.WriteLine(b1 && b2);
Console.WriteLine(b2 && b1);
}
}
然而,它甚至没有编译。它表示无法应用运营商'&amp;&amp;'到'MyStruct'和'MyStruct'类型的操作数。
我知道我可以实现&
运算符的重载。所以,让我们这样做。 &
必须返回MyStruct
,因此我无法返回bool
。
public static MyStruct operator &(MyStruct lhs, MyStruct rhs) {
return new MyStruct(lhs._i & rhs._i);
}
现在代码编译了。其输出为1
和-1
。因此b1 && b2
的结果与b2 && b1
的结果不同。
如果我调试代码,我会看到b1 && b2
首先执行false
上的b1
运算符,该运算符返回false
。然后它在b1和b2上执行&
运算符,执行按位,在1和-1上执行,结果为1.所以它确实首先检查b1是否为假。
第二个表达式b2 && b1
首先执行false
上的b2
运算符,该运算符返回true
。结合我使用短路的事实,它对b1
没有任何作用,只打印出b2
的值。
是的,当您使用短路时,false
运算符被执行。但是,它不会在第二个参数上执行true
或false
运算符,而是在操作数上执行重载的&
运算符。
这什么时候有用呢?或者我如何制作我的类型以便它可以检查这两个变量是否都是真的?
答案 0 :(得分:5)
您提到的404的内容可以在这里找到:
http://web.archive.org/web/20080613013350/http://www.ayende.com/Blog/archive/2006/08/04/7381.aspx
作者所指的文章在这里:
为了避免再次出现同样的问题,以下是本文的重点:
几个月前,我发布了关于我们的查询API以及它是如何工作的解释。我们的查询API允许我们使用强类型C#语法表达我们的查询:
List<Customer> customers = repository.FindAll(Customer.Columns.Age == 20 & Customer.Columns.Name == “foo”);
我在之前的帖子中指出的一件事是我无法超载&amp;&amp;和||操作员直接因为框架不允许这样的疯狂......至少不是直接的。
特别是,不能重载成员访问,方法调用或=,&amp;&amp;,||,?:,checked,unchecked,new,typeof,as和is运算符。 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/csspec/html/vclrfcsharpspec_7_2_2.asp
在过去的一个月里,我对这个主题进行了一些调查,看看我是否以及如何获得&amp;&amp;和||表现我想要的方式。今天晚上我遇到了MSDN上的条件逻辑运算符页面,它给了我正在寻找的答案:
操作x&amp;&amp; y被评估为T.false(x)? x:T。&amp;(x,y),其中T.false(x)是在T中声明的运算符false的调用,而T.&amp;(x,y)是所选运算符&amp;的调用。换句话说,首先计算x并在结果上调用operator false以确定x是否肯定为false。然后,如果x肯定是假的,则操作的结果是先前为x计算的值。否则,评估y,并选择运算符&amp;在先前为x计算的值和为y计算的值上调用,以生成操作的结果。 操作x || y被评估为T.true(x)? x:T。|(x,y),其中T.true(x)是在T中声明的运算符true的调用,而T. |(x,y)是所选运算符|的调用。换句话说,首先计算x并在结果上调用operator true以确定x是否肯定为真。然后,如果x绝对为真,则操作的结果是先前为x计算的值。否则,将评估y,并选择运算符|在先前为x计算的值和为y计算的值上调用,以生成操作的结果。 因为我们已经拥有了&amp;和|运算符到位只是一个重载真假操作符的问题都返回false。这导致&amp;和|操作员总是被调用,这反过来会导致两个标准对象变成AndCriteria / OrCriteria!
现在我们可以使用&amp;&amp;和&amp;和||我们习以为常的语法。
repository.FindAll(Customer.Columns.Age == 20 && Customer.Columns.Name == “foo”);
repository.FindAll(Customer.Columns.FirstName == “Foo” || Customer.Columns.LastName == “Bar”);
相关的运算符重载如下所示。
public static bool operator true(Criteria<T> criteria) {
return false;
}
public static bool operator false(Criteria<T> criteria) {
return false;
}
public static Criteria<T> operator &(Criteria<T> lhs, Criteria<T> rhs) {
return new AndCriteria<T>(lhs, rhs);
}
public static Criteria<T> operator |(Criteria<T> lhs, Criteria<T> rhs) {
return new OrCriteria<T>(lhs, rhs);
}
答案 1 :(得分:4)
修改 - 强>
阅读链接文章我能够得到以下输出,它使用了true和false运算符:
op false on 1
op & on 1 -1
op true on 1
op true on -1
FALSE
op false on -1
op true on -1
FALSE
op true on 1
op true on 1
TRUE
op true on -1
op & on -1 1
op true on -1
op true on 1
TRUE
使用代码:
class Program
{
static void Main(string[] args)
{
MyStruct b1 = new MyStruct(1); // to be considered true
MyStruct b2 = new MyStruct(-1); // to be considered false
Console.WriteLine((b1 && b2) ? "TRUE" : "FALSE");
Console.WriteLine((b2 && b1) ? "TRUE" : "FALSE");
Console.WriteLine((b1 || b2) ? "TRUE" : "FALSE");
Console.WriteLine((b2 || b1) ? "TRUE" : "FALSE");
Console.ReadLine();
}
}
public struct MyStruct
{
private int _i;
public MyStruct(int i)
{
_i = i;
}
public static bool operator true(MyStruct ms)
{
Console.WriteLine("op true on {0}", ms);
return ms._i > 0;
}
public static bool operator false(MyStruct ms)
{
Console.WriteLine("op false on {0}", ms);
return ms._i <= 0;
}
public static MyStruct operator &(MyStruct lhs, MyStruct rhs)
{
Console.WriteLine("op & on {0} {1}", lhs, rhs);
if (lhs)
{
return rhs;
}
else
{
return new MyStruct(-1); //-1 is false
}
}
public static MyStruct operator |(MyStruct lhs, MyStruct rhs)
{
Console.WriteLine("op & on {0} {1}", lhs, rhs);
if (lhs)
{
return lhs;
}
else
{
return rhs;
}
}
public override string ToString()
{
return this._i.ToString();
}
}
当你说第一个代码无法编译时,我不确定你的意思,虽然它没有使用运算符true / false,我在2010 express中运行了以下代码并得到了输出:
op bool on 1
op bool on -1
False
op bool on -1
False
op bool on -1
op bool on 1
True
op bool on 1
True
代码:
class Program
{
static void Main(string[] args)
{
MyStruct b1 = new MyStruct(1); // to be considered true
MyStruct b2 = new MyStruct(-1); // to be considered false
Console.WriteLine(b1 && b2);
Console.WriteLine(b2 && b1);
Console.WriteLine(b2 || b1);
Console.WriteLine(b1 || b2);
Console.ReadLine();
}
}
public struct MyStruct
{
private int _i;
public MyStruct(int i)
{
_i = i;
}
public static bool operator true(MyStruct ms)
{
Console.WriteLine("op true on {0}", ms);
return ms._i > 0;
}
public static bool operator false(MyStruct ms)
{
Console.WriteLine("op false on {0}", ms);
return ms._i <= 0;
}
public static implicit operator bool(MyStruct ms)
{
Console.WriteLine("op bool on {0}", ms);
return ms._i > 0;
}
public override string ToString()
{
return this._i.ToString();
}
}
答案 2 :(得分:1)
来自Microsoft(http://msdn.microsoft.com/en-us/library/6292hy1k.aspx):
在C#2.0之前,使用true和false运算符创建用户定义的 与诸如SqlBool之类的类型兼容的可空值类型。然而, 该语言现在提供对可空值类型的内置支持,以及 只要有可能,你应该使用它们而不是重载true和 虚假运营商。
如果您只想将对象评估为布尔值,请删除operator true和operator false overload,然后使用bool重载。
答案 3 :(得分:1)
回答你的上一个问题:“我如何制作我的类型,以便它可以检查两个变量是否都是真的?” - 只需使用&
运算符即可。 &&
的重点是短路,因此在没有必要时不检查第二个参数。
检查出来:
Console.WriteLine(b1 & b2); // outputs 1
Console.WriteLine(b2 & b1); // outputs 1
您实际上缺少一个重要的位,它允许您使用MyStruct(&
和|
)作为布尔值 - 隐式转换为bool
:
public static implicit operator bool(MyStruct ms) {
return ms._i > 0;
}
这允许您使用MyStruct(也是运算符的结果):
if (b1 & b2)
Console.WriteLine("foo");
最后,可能是最重要的,请注意:您的示例中的问题来自您要执行逻辑操作的事实(检查MyStruct
的2个实例是否为{{ 1}}),但是为了这个目的,您的true
运算符实现不正确。它在二进制算术方面起作用,当使用参数&
(MyStruct
)和1
({{1}调用时,产生值为MyStruct(1)
的{{1}}实例}})。所以它基本上是true
。这就是MyStruct(-1)
在您的示例中提供与false
不同的结果的原因。基于该运算符的任何其他逻辑将被破坏且不可预测。在(true & false) == true
和b1 && b2
方面以.NET实现的b2 && b1
行为证实了这一点。
编辑:您希望能够将&&
用作布尔值。您实现了运算符false
和&
,并期望MyStruct
和true
在布尔逻辑方面工作。但是,您在二进制算术(在false
字段上使用&&
)实现||
,这使得&
的此实现与您期望的布尔逻辑不兼容({ {1}},对&
布尔值的解释意味着int
。现在,请考虑&
通常不是逻辑运算符(它不返回(1 & -1) == 1
) - 它是一个实现为(true & false) == false
的短路。请注意,它会在您的案例中返回MyStruct
,您根据其字段的值将其解释为&&
或bool
。底线:您希望T.false(x) ? x : T.&(x, y)
对两个操作数进行逻辑测试,但MyStruct
的.NET实现使用您的true
实现,它与布尔逻辑不兼容期望的。
答案 4 :(得分:0)
真/假运算符的意思是提供布尔逻辑语义而无需隐式转换为bool
。
如果允许将类型隐式转换为bool
,则不再需要true / false运算符。但是,如果您只想显式转换或不转换,但仍希望将您的类型作为if
或while
表达中的条件,则可以使用true
和false
运算符。