菜鳥學(xué)堂:
c#中的三值邏輯類
三值邏輯的實(shí)際應(yīng)用價(jià)值并未被忽視,在絕大多數(shù)介紹關(guān)系型數(shù)據(jù)庫(kù)知識(shí)的書籍中,都涉及了null值的討論,也少不了三值邏輯。而msdn中,則給出了一個(gè)用c#實(shí)現(xiàn)的三值邏輯結(jié)構(gòu)(struct),在應(yīng)用層提供了三值邏輯運(yùn)算功能。相關(guān)文章轉(zhuǎn)貼如下:
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.
從文章內(nèi)容我們可以看出,它采用的是我們前面所述的第三種算法。這個(gè)示例搭建了一個(gè)不錯(cuò)的框架,除了與、或運(yùn)算,還包括了必要的類型轉(zhuǎn)換、比較以及在.net clr中必不可少的gethashcode和tostring方法。
當(dāng)我們以初學(xué)者的心態(tài)面對(duì)這段樸實(shí)的代碼時(shí),有幾個(gè)地方是值得學(xué)習(xí)的:
在結(jié)構(gòu)內(nèi)部,以-1、0、1來代表三種不同的邏輯狀態(tài)。并通過定義false、null、true三個(gè)常量來代表所有可能該類型對(duì)象所有可能的值。這種數(shù)值與邏輯的對(duì)應(yīng)符合人們常規(guī)的思維習(xí)慣和數(shù)學(xué)上的美感。也方便實(shí)現(xiàn)gethashcode方法。
利用內(nèi)部數(shù)值,簡(jiǎn)潔美觀的實(shí)現(xiàn)了與/或/非運(yùn)算。如果按照前面我們提的三種邏輯算法中的另外兩種,實(shí)現(xiàn)起來就沒有那么美觀了。也許這就是很多關(guān)系型數(shù)據(jù)庫(kù)選擇這種算法實(shí)現(xiàn)的原因。美感,在數(shù)學(xué)體系中是一件很重要的事。
提供了istrue、isfalse、isnull判斷功能,使用起來很方便。
三值邏輯向兩值邏輯和dbnull轉(zhuǎn)換時(shí),必須顯示轉(zhuǎn)型(explicit),反之則只需要隱式轉(zhuǎn)換(implicit)。
實(shí)現(xiàn)了true和false運(yùn)算符。
重載了.net clr要求的gethashcode和tostring方法。當(dāng)我們?cè)谔囟ǖ沫h(huán)境工作時(shí),應(yīng)該遵循該環(huán)境的要求和約定,而這是實(shí)際開發(fā)時(shí)經(jīng)常被忽視的。
為了滿足實(shí)際使用的需要,我對(duì)這個(gè)類進(jìn)行了一些擴(kuò)充。主要如下:
與dbnull類型的互相轉(zhuǎn)化(要考慮其中的類型轉(zhuǎn)換異常)。
從字符串到三值邏輯的解析方法parse(據(jù)此對(duì)tostring()方法有所改變)。
增加了新的構(gòu)造函數(shù)。
增加了支持另外兩種邏輯運(yùn)算體系的與/或運(yùn)算。
增加了向數(shù)據(jù)庫(kù)邏輯字段賦值所用的轉(zhuǎn)換函數(shù)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>
/// 從數(shù)據(jù)庫(kù)組件的邏輯字段值中構(gòu)造實(shí)例
/// </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事實(shí)上是一種以null值為最低優(yōu)先級(jí)的邏輯與操作。通常用于驗(yàn)證數(shù)據(jù)有效性。
/// 兩個(gè)操作數(shù)中至少有一個(gè)為false時(shí)返回false,否則,至少有一個(gè)為true時(shí)為true,否
/// 則返回null。
/// </summary>
/// <param name="x">左操作數(shù)</param>
/// <param name="y">右操作數(shù)</param>
/// <returns>運(yùn)算結(jié)果為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事實(shí)上是一種以null值為最低優(yōu)先級(jí)的邏輯或操作。通常用于驗(yàn)證數(shù)據(jù)有效性。
/// 兩個(gè)操作數(shù)中至少有一個(gè)為true時(shí)返回true,否則,至少有一個(gè)為false時(shí)返回false,否
/// 則返回null。
/// </summary>
/// <param name="x">左操作數(shù)</param>
/// <param name="y">右操作數(shù)</param>
/// <returns>運(yùn)算結(jié)果為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值為最高優(yōu)先值的邏輯與操作,常見于某些數(shù)據(jù)庫(kù)平臺(tái)。當(dāng)操作數(shù)中有一個(gè)為
/// null,返回值為null,其它與二值邏輯相同。
/// </summary>
/// <param name="x">左操作數(shù)</param>
/// <param name="y">右操作數(shù)</param>
/// <returns>運(yùn)算結(jié)果為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值為最高優(yōu)先值的邏輯或操作,常見于某些數(shù)據(jù)庫(kù)平臺(tái)。當(dāng)操作數(shù)中有一個(gè)為
/// null,返回值為null,其它與二值邏輯相同。
/// </summary>
/// <param name="x">左操作數(shù)</param>
/// <param name="y">右操作數(shù)</param>
/// <returns>運(yùn)算結(jié)果為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>
/// 用于向數(shù)據(jù)庫(kù)訪問組件的boolean類型(如sqldbtype.bit)字段賦值
/// </summary>
/// <returns>返回一個(gè)object對(duì)象,其內(nèi)部封裝的可能為true、false或dbnull.value</returns>
public object todbboolean()
{
return (value == 0) ? (object)dbnull.value : (object)(value>0);
}
}
}
以上代碼經(jīng)實(shí)際應(yīng)用,可以滿足需求,但是有如下地方還值得進(jìn)一步改造:
應(yīng)當(dāng)將三種邏輯體系放在同一個(gè)類型中實(shí)現(xiàn)顯得很不協(xié)調(diào),影響了代碼一致性和我們的常規(guī)使用習(xí)慣。應(yīng)當(dāng)將通用的代碼統(tǒng)一生成為一個(gè)基類,并用抽象方法或接口的形式規(guī)定出與/或運(yùn)算實(shí)現(xiàn)。在三個(gè)不同的子類中實(shí)現(xiàn)。并在子類中實(shí)現(xiàn)不同子類之間的顯示類型轉(zhuǎn)換。為了出現(xiàn)不必要的強(qiáng)耦合,可以實(shí)現(xiàn)子類向基類的隱式類型轉(zhuǎn)換(由于oo語言的特性,這一點(diǎn)默認(rèn)情況下就是有效的)以及基類向子類的顯式類型轉(zhuǎn)換(這一點(diǎn)可以通過在基類中定義一個(gè)虛構(gòu)造函數(shù),由子類直接繼承實(shí)現(xiàn))。