zoukankan      html  css  js  c++  java
  • 蛙蛙推荐:利用操作符重载提高程序的可读性

    摘要:以前做过一个简单的ORMapping的小组件,但c#代码转换成SQL代码的部分不是很直观,用到了很多丑陋的方法名来代替操作符,今天受脑袋指点,其实可以用操作符重载来实现c#直接写数据查询条件。

      c#可以重载很多操作符,对于SQL操作来说,主要是 ==,!=,&&,||(为了演示简单,暂不实现!,<,>,<=,>=等),其中前两个重载的话,还得必须重载true和false操作符,后两个不能直接重载,但可以重载&和|来代替。

    我们先定义一个表示数据库查询条件的类,如下

    代码
    public class DbCondition {
    public readonly string _fieldName = string.Empty;
    public string _sql = string.Empty;
    public DbCondition(string fieldName) {
    _fieldName
    = fieldName;
    }
    }

    有一些SQL的语法元素,如like,between,in在c#里没有对应的操作符,所以我们只能以方法的形式来实现它们了。

    代码
    private DbCondition() { }
    public DbCondition Like(string like) {
    DbCondition result
    = new DbCondition();
    result._sql
    = string.Format("{0} like '{1}'", _fieldName, like);
    return result;
    }
    public DbCondition Between(DateTime dt1, DateTime dt2) {
    DbCondition result
    = new DbCondition();
    result._sql
    = string.Format("{0} between '{1}' and '{2}'", _fieldName, dt1, dt2);
    return result;
    }



    public DbCondition In(IEnumerable<int> arr) {
    DbCondition result
    = new DbCondition();
    StringBuilder sb
    = new StringBuilder();
    foreach (int item in arr) {
    sb.AppendFormat(
    "{0},", item);
    }
    sb.Remove(sb.Length
    - 1, 1);
    result._sql
    = string.Format("{0} in ({1})", _fieldName, sb);
    return result;
    }
    public DbCondition In(IEnumerable<string> arr) {
    DbCondition result
    = new DbCondition();
    StringBuilder sb
    = new StringBuilder();
    foreach (string item in arr) {
    sb.AppendFormat(
    "'{0}',", item);
    }
    sb.Remove(sb.Length
    - 1, 1);
    result._sql
    = string.Format("{0} in ({1})", _fieldName, sb);
    return result;
    }

    现在轮到那些等于,不等于,与和或的实现了,其中逻辑运算符&和|的参数是能是两个同类型的参数,而比较操作符的第二个参数就可以是任意类型了,比如常见的int,bool,string,每个操作符重载的实现也比较简单,主要是操作_sql字段,拼写成SQL。

    代码
    public static DbCondition operator &(DbCondition x, DbCondition y) {
    DbCondition result
    = new DbCondition();
    result._sql
    = string.Format(" {0} and {1} ", x._sql, y._sql);
    return result;
    }
    public static DbCondition operator |(DbCondition x, DbCondition y) {
    DbCondition result
    = new DbCondition();
    result._sql
    = string.Format(" {0} or {1} ", x._sql, y._sql);
    return result;
    }
    public static DbCondition operator ==(DbCondition x, int y) {
    DbCondition result
    = new DbCondition();
    result._sql
    = string.Format("{0} = {1}", x._fieldName, y);
    return result;
    }
    public static DbCondition operator !=(DbCondition x, int y) {
    DbCondition result
    = new DbCondition();
    result._sql
    = string.Format("{0} <> {1}", x._fieldName, y);
    return result;
    }
    public static DbCondition operator ==(DbCondition x, string y) {
    DbCondition result
    = new DbCondition();
    result._sql
    = string.Format("{0} = '{1}'", x._fieldName, y);
    return result;
    }
    public static DbCondition operator !=(DbCondition x, string y) {
    DbCondition result
    = new DbCondition();
    result._sql
    = string.Format("{0} <> '{1}'", x._fieldName, y);
    return result;
    }
    public static DbCondition operator ==(DbCondition x, bool y) {
    DbCondition result
    = new DbCondition();
    result._sql
    = string.Format("{0} = {1}", x._fieldName, y ? 1 : 0);
    return result;
    }
    public static DbCondition operator !=(DbCondition x, bool y) {
    DbCondition result
    = new DbCondition();
    result._sql
    = string.Format("{0} <> {1}", x._fieldName, y ? 1 : 0);
    return result;
    }

    因为我们重载了比较操作符和逻辑操作符,而一个bool表达式有短路的问题,比如一个或关系连接的两个bool表达式,如果左边的表达式返回false,右边的表达式就不执行了,所以我们还得重载true和false两个操作符,让他都返回false,如下

    public static bool operator false(DbCondition x) { return false; }
    public static bool operator true(DbCondition x) { return false; }

    OK,剩下的都是一些常规的重载了,都是统一的套路

    代码
    public override bool Equals(object obj) {
    DbCondition cond
    = obj as DbCondition;
    if (cond == null) return false;
    if (object.ReferenceEquals(this, cond) == true) return true;
    if (cond._fieldName != this._fieldName) return false;
    if (cond._sql != this._sql) return false;
    return true;
    }
    public override int GetHashCode() {
    int hashcode = 0;
    if (!string.IsNullOrEmpty(_fieldName)) hashcode ^= _fieldName.GetHashCode();
    if (!string.IsNullOrEmpty(_sql)) hashcode ^= _sql.GetHashCode() << 1;
    return hashcode;
    }

    public override string ToString() {
    return _sql;
    }

    下面开始准备测试了,先准备一个实体类,该实体类包含一些静态的条件,分别对应数据库表的列,真实情况下,这些实体类是由代码生成器生成的。

    代码
    public class User {

    public static DbCondition CdtUserId { get { return new DbCondition("UserId"); } }
    public static DbCondition CdtName { get { return new DbCondition("Name"); } }
    public static DbCondition CdtNickName { get { return new DbCondition("NickName"); } }
    public static DbCondition CdtSex { get { return new DbCondition("Sex"); } }
    public static DbCondition CdtRegistTime { get { return new DbCondition("RegistTime"); } }
    }

    写一些测试代码,看下效果

    代码
    Console.WriteLine(User.CdtName == "蛙蛙");
    Console.WriteLine(User.CdtName
    == "蛙蛙" || User.CdtNickName == "蛙蛙");
    Console.WriteLine(User.CdtName
    == "蛙蛙" && User.CdtSex == true);
    Console.WriteLine(User.CdtName.Like(
    "蛙蛙%")
    && User.CdtRegistTime.Between(DateTime.Now.AddMonths(-1), DateTime.Now));
    Console.WriteLine(User.CdtNickName
    != "蛙蛙"
    && User.CdtUserId.In(Enumerable.Range(100,10)));

    测试输出如下

    代码
    Name = '蛙蛙'
    Name
    = '蛙蛙' or NickName = '蛙蛙'
    Name
    = '蛙蛙' and Sex = 1
    Name like
    '蛙蛙%' and RegistTime between '2010-7-9 22:27:11' and '2010-8-9 22:2
    7:11'
    NickName <> '蛙蛙' and UserId in (100,101,102,103,104,105,106,107,108,109)

    这样写出来的对象查询语句和LINQ格式差不多了,很直观,而且生成的SQL也可以自由控制。

    相关链接

    Operator Overloading Tutorial

    蛙蛙推荐:简化基于数据库的DotNet应用程序开发

  • 相关阅读:
    台州 OJ 3847 Mowing the Lawn 线性DP 单调队列
    洛谷 OJ P1417 烹调方案 01背包
    快速幂取模
    台州 OJ 2649 More is better 并查集
    UVa 1640
    UVa 11971
    UVa 10900
    UVa 11346
    UVa 10288
    UVa 1639
  • 原文地址:https://www.cnblogs.com/onlytiancai/p/Operator_Overloading.html
Copyright © 2011-2022 走看看