菜鸟学堂: 
c#中的三值逻辑类
三值逻辑的实际应用价值并未被忽视,在绝大多数介绍关系型数据库知识的书籍中,都涉及了null值的讨论,也少不了三值逻辑。而msdn中,则给出了一个用c#实现的三值逻辑结构(struct),在应用层提供了三值逻辑运算功能。相关文章转贴如下:
c# language specification
 
 
11.4.2 database boolean type
the dbbool struct below implements a three-valued logical type. the possible values of this type are dbbool.true, dbbool.false, and dbbool.null, where the null member indicates an unknown value. such three-valued logical types are commonly used in databases.
using system;
public struct dbbool
{
 // the three possible dbbool values.
 public static readonly dbbool null = new dbbool(0);
 public static readonly dbbool false = new dbbool(-1);
 public static readonly dbbool true = new dbbool(1);
 // private field that stores –1, 0, 1 for false, null, true.
 sbyte value;
 // private instance constructor. the value parameter must be –1, 0, or 1.
 dbbool(int value) {
 this.value = (sbyte)value;
 }
 // properties to examine the value of a dbbool. return true if this
 // dbbool has the given value, false otherwise.
 public bool isnull { get { return value == 0; } }
 public bool isfalse { get { return value < 0; } }
 public bool istrue { get { return value > 0; } }
 // implicit conversion from bool to dbbool. maps true to dbbool.true and
 // false to dbbool.false.
 public static implicit operator dbbool(bool x) {
 return x? true: false;
 }
 // explicit conversion from dbbool to bool. throws an exception if the
 // given dbbool is null, otherwise returns true or false.
 public static explicit operator bool(dbbool x) {
 if (x.value == 0) throw new invalidoperationexception();
 return x.value > 0;
 }
 // equality operator. returns null if either operand is null, otherwise
 // returns true or false.
 public static dbbool operator ==(dbbool x, dbbool y) {
 if (x.value == 0 || y.value == 0) return null;
 return x.value == y.value? true: false;
 }
 // inequality operator. returns null if either operand is null, otherwise
 // returns true or false.
 public static dbbool operator !=(dbbool x, dbbool y) {
 if (x.value == 0 || y.value == 0) return null;
 return x.value != y.value? true: false;
 }
 // logical negation operator. returns true if the operand is false, null
 // if the operand is null, or false if the operand is true.
 public static dbbool operator !(dbbool x) {
 return new dbbool(-x.value);
 }
 // logical and operator. returns false if either operand is false,
 // otherwise null if either operand is null, otherwise true.
 public static dbbool operator &(dbbool x, dbbool y) {
 return new dbbool(x.value < y.value? x.value: y.value);
 }
 // logical or operator. returns true if either operand is true, otherwise
 // null if either operand is null, otherwise false.
 public static dbbool operator |(dbbool x, dbbool y) {
 return new dbbool(x.value > y.value? x.value: y.value);
 }
 // definitely true operator. returns true if the operand is true, false
 // otherwise.
 public static bool operator true(dbbool x) {
 return x.value > 0;
 }
 // definitely false operator. returns true if the operand is false, false
 // otherwise.
 public static bool operator false(dbbool x) {
 return x.value < 0;
 }
 public override bool equals(object obj) {
 if (!(obj is dbbool)) return false;
 return value == ((dbbool)obj).value;
 }
 public override int gethashcode() {
 return value;
 }
 public override string tostring() {
 if (value > 0) return "dbbool.true";
 if (value < 0) return "dbbool.false";
 return "dbbool.null";
 }
}
--------------------------------------------------------------------------------
send feedback on this topic to microsoft
© microsoft corporation. all rights reserved.
从文章内容我们可以看出,它采用的是我们前面所述的第三种算法。这个示例搭建了一个不错的框架,除了与、或运算,还包括了必要的类型转换、比较以及在.net clr中必不可少的gethashcode和tostring方法。
当我们以初学者的心态面对这段朴实的代码时,有几个地方是值得学习的:
在结构内部,以-1、0、1来代表三种不同的逻辑状态。并通过定义false、null、true三个常量来代表所有可能该类型对象所有可能的值。这种数值与逻辑的对应符合人们常规的思维习惯和数学上的美感。也方便实现gethashcode方法。
利用内部数值,简洁美观的实现了与/或/非运算。如果按照前面我们提的三种逻辑算法中的另外两种,实现起来就没有那么美观了。也许这就是很多关系型数据库选择这种算法实现的原因。美感,在数学体系中是一件很重要的事。
提供了istrue、isfalse、isnull判断功能,使用起来很方便。
三值逻辑向两值逻辑和dbnull转换时,必须显示转型(explicit),反之则只需要隐式转换(implicit)。
实现了true和false运算符。
重载了.net clr要求的gethashcode和tostring方法。当我们在特定的环境工作时,应该遵循该环境的要求和约定,而这是实际开发时经常被忽视的。
为了满足实际使用的需要,我对这个类进行了一些扩充。主要如下:
与dbnull类型的互相转化(要考虑其中的类型转换异常)。
从字符串到三值逻辑的解析方法parse(据此对tostring()方法有所改变)。
增加了新的构造函数。
增加了支持另外两种逻辑运算体系的与/或运算。
增加了向数据库逻辑字段赋值所用的转换函数todbboolean。
新的代码如下:
using system;
namespace march.vboolean
{
 /// <summary>
 /// 三值逻辑类(bool with three),支持system.dbnull。
 /// </summary>
 public struct boolw3
 {
 // the three possible boolw3 values.
 public static readonly boolw3 null = new boolw3(0);
 public static readonly boolw3 false = new boolw3(-1);
 public static readonly boolw3 true = new boolw3(1);
 // private field that stores –1, 0, 1 for false, null, true.
 sbyte value;
 // private instance constructor. the value parameter must be –1, 0, or 1.
 boolw3(int value) 
 {
 this.value = (sbyte)value;
 }
 public boolw3(bool value)
 {
 this.value = value? (sbyte)1:(sbyte)-1;
 }
 public boolw3(dbnull value)
 {
 this.value = (sbyte)0;
 }
 /// <summary>
 /// 从数据库组件的逻辑字段值中构造实例
 /// </summary>
 /// <param name="?">只能为system.boolean或dbnull类型。</param>
 public boolw3(object value)
 {
 if(null == value)
 throw new argumentexception("the value must in true, false or dbnull!");
 if(value.gettype() == typeof(bool))
 {
 this.value = (bool)value?(sbyte)1:(sbyte)-1;
 return;
 }
 if(value.gettype() == typeof(dbnull))
 {
 this.value = (sbyte)0;
 return;
 }
 throw new argumentexception("the value must in true, false or dbnull!");
 }
 /// <summary>
 /// 从字符串解析值。
 /// </summary>
 /// <param name="value">可选值为可能带有限定名"boolw3"的"true"、"false"、"null"</param>
 public static boolw3 parse(string value)
 {
 boolw3 re = null;
 switch(value)
 {
 case "boolw3.true":
 case "true" :
 {
 re.value = (sbyte)1;
 break;
 }
 case "boolw3.false":
 case "false":
 {
 re.value = (sbyte)-1;
 break;
 }
 case "boolw3.null":
 case "null":
 {
 re.value = (sbyte)0;
 break;
 }
 default:
 throw new argumentexception("the value must in /"boolw3.true/", /"boolw3.false/" ,/"boolw3.null/", /"true/", /"false/" or /"null/"!");
 }
 return re;
 }
 // properties to examine the value of a boolw3. return true if this
 // boolw3 has the given value, false otherwise.
 public bool isnull { get { return value == 0; } }
 public bool isfalse { get { return value < 0; } }
 public bool istrue { get { return value > 0; } }
 // implicit conversion from bool to boolw3. maps true to boolw3.true and
 // false to boolw3.false.
 public static implicit operator boolw3(bool x) 
 {
 return x? true: false;
 }
 public static implicit operator boolw3(dbnull x)
 {
 return null;
 }
 // explicit conversion from boolw3 to bool.throws an exception if the
 // given boolw3 is null, otherwise returns true or false.
 public static explicit operator bool(boolw3 x) 
 {
 if (x.value == 0) throw new invalidoperationexception();
 return x.value > 0;
 }
 public static explicit operator dbnull(boolw3 x)
 {
 if (x.value != 0) throw new invalidoperationexception();
 return dbnull.value;
 }
 // equality operator. returns null if either operand is null, otherwise
 // returns true or false.
 public static boolw3 operator ==(boolw3 x, boolw3 y) 
 {
 if (x.value == 0 || y.value == 0) return null;
 return x.value == y.value? true: false;
 }
 // inequality operator. returns null if either operand is null, otherwise
 // returns true or false.
 public static boolw3 operator !=(boolw3 x, boolw3 y) 
 {
 if (x.value == 0 || y.value == 0) return null;
 return x.value != y.value? true: false;
 }
 // logical negation operator. returns true if the operand is false, null
 // if the operand is null, or false if the operand is true.
 public static boolw3 operator !(boolw3 x) 
 {
 return new boolw3(-x.value);
 }
 // logical and operator. returns false if either operand is false,
 // otherwise null if either operand is null, otherwise true.
 public static boolw3 operator &(boolw3 x, boolw3 y)
 {
 return new boolw3(x.value < y.value? x.value: y.value);
 }
 // logical or operator. returns true if either operand is true, otherwise
 // null if either operand is null, otherwise false.
 public static boolw3 operator |(boolw3 x, boolw3 y)
 {
 return new boolw3(x.value > y.value? x.value: y.value);
 }
 /// <summary>
 /// verifyand事实上是一种以null值为最低优先级的逻辑与操作。通常用于验证数据有效性。
 /// 两个操作数中至少有一个为false时返回false,否则,至少有一个为true时为true,否
 /// 则返回null。
 /// </summary>
 /// <param name="x">左操作数</param>
 /// <param name="y">右操作数</param>
 /// <returns>运算结果为boolw3类型</returns>
 public static boolw3 verifyand(boolw3 x, boolw3 y)
 {
 if (x.value == -1 || y.value == -1) return false;
 if (x.value == 1 || y.value == 1) return true;
 return null;
 }
 /// <summary>
 /// verifyor事实上是一种以null值为最低优先级的逻辑或操作。通常用于验证数据有效性。
 /// 两个操作数中至少有一个为true时返回true,否则,至少有一个为false时返回false,否
 /// 则返回null。
 /// </summary>
 /// <param name="x">左操作数</param>
 /// <param name="y">右操作数</param>
 /// <returns>运算结果为boolw3类型</returns>
 public static boolw3 verifyor(boolw3 x, boolw3 y)
 {
 if (x.value == 1 || y.value == 1) return true;
 if (x.value == -1 & y.value == -1) return false;
 return true;
 }
 
 /// <summary>
 /// dband是以null值为最高优先值的逻辑与操作,常见于某些数据库平台。当操作数中有一个为
 /// null,返回值为null,其它与二值逻辑相同。
 /// </summary>
 /// <param name="x">左操作数</param>
 /// <param name="y">右操作数</param>
 /// <returns>运算结果为boolw3类型</returns>
 public static boolw3 dband(boolw3 x, boolw3 y)
 {
 if (x.value == 0 || y.value ==0) return null;
 return new boolw3(x.value < y.value ? x.value : y.value);
 }
 /// <summary>
 /// dbor是以null值为最高优先值的逻辑或操作,常见于某些数据库平台。当操作数中有一个为
 /// null,返回值为null,其它与二值逻辑相同。
 /// </summary>
 /// <param name="x">左操作数</param>
 /// <param name="y">右操作数</param>
 /// <returns>运算结果为boolw3类型</returns>
 public static boolw3 dbor(boolw3 x, boolw3 y)
 {
 if (x.value == 0 || y.value ==0) return null;
 return new boolw3(x.value > y.value ? x.value : y.value);
 }
 
 // definitely true operator. returns true if the operand is true, false
 // otherwise.
 public static bool operator true(boolw3 x) 
 {
 return x.value > 0;
 }
 // definitely false operator. returns true if the operand is false, false
 // otherwise.
 public static bool operator false(boolw3 x) 
 {
 return x.value < 0;
 }
 public override bool equals(object obj) 
 {
 if (!(obj is boolw3)) return false;
 return value == ((boolw3)obj).value;
 }
 public override int gethashcode() 
 {
 return value;
 }
 public override string tostring() 
 {
 if (value > 0) return "boolw3.true";
 if (value < 0) return "boolw3.false";
 return "boolw3.null";
 }
 /// <summary>
 /// 用于向数据库访问组件的boolean类型(如sqldbtype.bit)字段赋值
 /// </summary>
 /// <returns>返回一个object对象,其内部封装的可能为true、false或dbnull.value</returns>
 public object todbboolean()
 {
 return (value == 0) ? (object)dbnull.value : (object)(value>0);
 }
 }
}
以上代码经实际应用,可以满足需求,但是有如下地方还值得进一步改造:
应当将三种逻辑体系放在同一个类型中实现显得很不协调,影响了代码一致性和我们的常规使用习惯。应当将通用的代码统一生成为一个基类,并用抽象方法或接口的形式规定出与/或运算实现。在三个不同的子类中实现。并在子类中实现不同子类之间的显示类型转换。为了出现不必要的强耦合,可以实现子类向基类的隐式类型转换(由于oo语言的特性,这一点默认情况下就是有效的)以及基类向子类的显式类型转换(这一点可以通过在基类中定义一个虚构造函数,由子类直接继承实现)。