达达's 胡搞瞎搞工作室

此Blog搬到www.unbe.cn 去了,要找我讨论问题请到我的新Blog

泛型的运算符重载

    前些天,跟园里的henry谈到了泛型的运算符重载,henry目前做的SQL Artisan对SQL语句进行了封装,避免了SQL语句无法在编译时期进行错误判断的缺陷,又保持了SQL语句的灵活性,但是目前SQL Artisan不支持泛型,hanry还没做过泛型的运算符重载,他觉得好像不能实现。今天早上起床时我试验了下,发现泛型的运算符重载是可以实现的,用泛型可以省掉很多的代码。

    假设我们不使用泛型,要对SQL语句进行封装,让我们的C#语句最后可以生成SQL语句,并且要保持类型安全性,例如代码 :

TableA.CreateTime == DateTime.Now & TableB.Name == "Peter"

,并且TableA.CreateTime == DateTime.Now换成TableA.CreateTime == "2007-7-13" 时编译不能通过,那么我们是不是需要为每种SQL数据类新封装一个类,用来做SQL语句生成之用,除了为每种类型封装一个类外我想不到别的更好的办法,但是如果泛型支持运算符重载,那么我们的代码就可以节省很多了,可能光说大家不太理解。

    现在我们就来看看泛型类的运算符是怎么重载的,怎样实际减少我们的代码量的。

    假设这里我们要对SQL的条件语句进行封装并让其支持泛型,SQL条件语句类我命名为SqlFilter,SQL语句类我命名为SqlExpression

    我的简单封装结果如下(这里没有用到数据库参数,但是实际应用中应该考虑使用数据库参数而不是单纯字符串连接):

    public class SqlFilter<T>
    
{
        
private string _name = null;

        
public string Name
        
{
            
get return _name; }
        }


        
public SqlFilter(string name)
        
{
            _name 
= name;
        }


        
public static SqlExpression operator ==(SqlFilter<T> t, T value)
        
{
            SqlExpression _exp 
= new SqlExpression(string.Format("{0} = '{1}'", t.Name, value.ToString()));
            
return _exp;
        }


        
public static SqlExpression operator !=(SqlFilter<T> t, T value)
        
{
            SqlExpression _exp 
= new SqlExpression(string.Format("{0} <> '{1}'", t.Name, value.ToString()));
            
return _exp;
        }


        
public override int  GetHashCode()
        
{
          
return base.GetHashCode();
        }

    }


    
public class SqlExpression
    
{
        
public string _expression;
        
public IDataParameter[] _parameters;

        
public SqlExpression(string expression, params IDataParameter[] patameters)
        
{
            _expression 
= expression;
            _parameters 
= patameters;
        }


        
public override string ToString()
        
{
            
return _expression;
        }


        
public IDataParameter[] Parameters
        
{
            
get return _parameters; }
        }


        
public IDataParameter this[int index]
        
{
            
get return this._parameters[index]; }
        }


        
public static string operator &(SqlExpression exp1, SqlExpression exp2)
        
{
            
return string.Format("{0} And {1}", exp1, exp2);
        }


        
public static string operator |(SqlExpression exp1, SqlExpression exp2)
        
{
            
return string.Format("{0} Or {1}", exp1, exp2);
        }

    }

    当T为DateTime类型时==运算符就接收DateTime类型的值,T为int类型时==运算符就接收int型的值,如果值类型和T的类型不匹配编译不通过。    

    我们可以写个简单的测试代码:

    class Program
    
{
        
static void Main(string
[] args)
        
{
            SqlFilter
<DateTime> _mc1 = new SqlFilter<DateTime>("TimeValue"
);
            SqlFilter
<int> _mc2 = new SqlFilter<int>("IntValue"
);

            Console.WriteLine(_mc1 
== DateTime.Now & _mc2 == 100
);
            Console.WriteLine(_mc1 
== DateTime.Now | _mc2 != 100
);
            
            Console.Read();
        }

    }

    运行下看看结果,如预计效果一样。

    我一开始也怀疑会不会失去了类型判断,我就把_mc1 == DateTime.Now 改成了 _mc1 == "123",果然编译不通过,呵呵,看来泛型的运算符重载还是有效的,henry的SQL Artisan不知道会不会开始考虑支持翻型,我的简陋持久层是肯定要用这样形式封装下SQL条件的。

    全部代码(推荐使用Snippet Compiler直接运行,不用再新建项目):

全部代码

posted on 2006-07-13 09:51  BG5SBK  阅读(2339)  评论(10编辑  收藏  举报

导航