泛型的运算符重载
前些天,跟园里的henry谈到了泛型的运算符重载,henry目前做的SQL Artisan对SQL语句进行了封装,避免了SQL语句无法在编译时期进行错误判断的缺陷,又保持了SQL语句的灵活性,但是目前SQL Artisan不支持泛型,hanry还没做过泛型的运算符重载,他觉得好像不能实现。今天早上起床时我试验了下,发现泛型的运算符重载是可以实现的,用泛型可以省掉很多的代码。
假设我们不使用泛型,要对SQL语句进行封装,让我们的C#语句最后可以生成SQL语句,并且要保持类型安全性,例如代码 :
,并且TableA.CreateTime == DateTime.Now换成TableA.CreateTime == "2007-7-13" 时编译不能通过,那么我们是不是需要为每种SQL数据类新封装一个类,用来做SQL语句生成之用,除了为每种类型封装一个类外我想不到别的更好的办法,但是如果泛型支持运算符重载,那么我们的代码就可以节省很多了,可能光说大家不太理解。
现在我们就来看看泛型类的运算符是怎么重载的,怎样实际减少我们的代码量的。
假设这里我们要对SQL的条件语句进行封装并让其支持泛型,SQL条件语句类我命名为SqlFilter,SQL语句类我命名为SqlExpression
我的简单封装结果如下(这里没有用到数据库参数,但是实际应用中应该考虑使用数据库参数而不是单纯字符串连接):
{
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的类型不匹配编译不通过。
我们可以写个简单的测试代码:
{
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直接运行,不用再新建项目):