.net泛型通用函数的特殊问题的解决方法
自从2.0版本的net framework推出之后泛型(Generic)得到了广泛好评。它不必像object类型一样性能上因为“拆箱”或者“装箱”得到损失,同时在编译语法检测阶段就可以实时检测出传入或者传出的类型是否符合特定条件。
但“金无赤足,人无完人”——在我们享受这些幸福编程的同时,泛型自身类型的不确定也带来了一个显著的问题——无法进行运算符重载。譬如现在我要写一个函数(一个通用的选择排序算法,使用泛型T),该怎么办呢?如果你简单使用这样的代码(C#如下):
//从小到大,改进型选择排序算法
public static void Sort<T>(T[] array)
{
bool flag = false; //标记是否已经排序
for(int i=0;i<array.Length-1;++i)
{
flag = false; //每次假定都已经排序,无须再排序
for(int j=i+1;i<array.Length;++j)
{
if(array[i]>array[j])
{
int temp = array[i];
array[i]=array[j];
array[j]=templ
flag = true; //已经排序
}
}
if(!flag)
{
break;
}
}
}
编译之后很快发现提示“运算符‘>'无法作用于T”一类的提示。
为什么呢?我们知道,凡是可以进行大于、小于比较的类型肯定都定义了运算符重载。一般类必须为此定义方可进行比较,不然大于号或者小于号(或者其它运算符)无法知道如何比较而发生错误。那么泛型因为事先都不知道什么类型?编译器检查器自然无法推断你运行时动态传入的这个类型一定保证是实现了运算符重载,严格语法检查情况下就自然报错。
怎么办呢?强制规定泛型T必须实现比较器(强制T必须实现IComparable,或者类似接口)。
public static void Sort<T>(T[] array)where T:IComparable
{
bool flag = false; //标记是否已经排序
for(int i=0;i<array.Length-1;++i)
{
flag = false; //每次假定都已经排序,无须再排序
for(int j=i+1;i<array.Length;++j)
{
if(array[i].Compare(array[j])>0)
{
int temp = array[i];
array[i]=array[j];
array[j]=templ
flag = true; //已经排序
}
}
if(!flag)
{
break;
}
}
}
一旦对泛型进行约束,那么泛型必然是实现该接口的类,必然拥有此方法(Compare方法返回结果int类型,如果大于0表示前面一个数字大于后面一个)。
当然,微软类库中有一个Comparer静态类,已经实现了此接口可以直接进行比较(http://msdn.microsoft.com/zh-cn/library/system.collections.comparer.comparer.aspx),因此我们也可以选择直接使用这个静态类中的Compare方法得到结果。
【例2】实现一个通用的“+”——即如果传入的字符串,则自动按照字符串进行字符拼接;如果传入的是其它基本类型(int,double等),则返回相加结果。
微软没有为“+”预定义接口,因此无法直接使用接口的方式来做(当然你自己强制定义一个,也可以如法炮制)。我们现在换一个方法——使用表达式树(C#代码如下):
public static T Add<T>(T a, T b)
{
Expression left = Expression.Constant(a);
Expression right = Expression.Constant(b);
Type t = typeof(T);
Expression value;
if (t == typeof(string))
{
value = Expression.Constant(a.ToString()+b.ToString());
}
else
{
value = Expression.Add(left, right);
}
Expression<Func<T>> addExp = Expression.Lambda<Func<T>>(value);
Func<T> addFunc = addExp.Compile();
return addFunc();
}
动态判断T是string还是其它基本类型,然后调用不同的方法组合成为表达式树,动态编译成为一个Func表达式,返回结果即可。
相关文章
php 中file_get_contents超时问题的解决方法
file_get_contents超时我知道最多的原因就是你机器访问远程机器过慢,导致php脚本超时了,但也有其它很多原因,下面我来总结file_get_contents超时问题的解决方法总结。...2016-11-25- 相信很多站长都遇到过这样一个问题,访问页面时出现408错误,下面一聚教程网将为大家介绍408错误出现的原因以及408错误的解决办法。 HTTP 408错误出现原因: HTT...2017-01-22
安卓手机wifi打不开修复教程,安卓手机wifi打不开解决方法
手机wifi打不开?让小编来告诉你如何解决。还不知道的朋友快来看看。 手机wifi是现在生活中最常用的手机功能,但是遇到手机wifi打不开的情况该怎么办呢?如果手机wifi...2016-12-21- 最近想自学PHP ,做了个验证码,但不知道怎么搞的,总出现一个如下图的小红叉,但验证码就是显示不出来,原因如下 未修改之前,出现如下错误; (1)修改步骤如下,原因如下,原因是apache权限没开, (2)点击打开php.int., 搜索extension=ph...2013-10-04
连接MySql速度慢的解决方法(skip-name-resolve)
最近在Linux服务器上安装MySql5后,本地使用客户端连MySql速度超慢,本地程序连接也超慢。 解决方法:在配置文件my.cnf的[mysqld]下加入skip-name-resolve。原因是默认安装的MySql开启了DNS的反向解析。如果禁用的话就不能...2015-10-21总结android studio注意事项及打不开等问题解决方法
经过一段时间的使用,总结了android studio打不开等问题的6种解决方法及android studio注意事项,希望对大家有所帮助。 1 首次运行,建立好项目需要下载一些东西,如果...2016-09-20MySQL ERROR 2013 (HY000)错误解决方法
当通过 TCP/IP 连接 MySQL 远程主机时,出现 ERROR 2013 (HY000): Lost connection to MySQL server at 'reading initial communication packet', system error: 104 。如果是在linux shell命令行中直接打 mysql 命令,...2015-03-15IE6-IE9中tbody的innerHTML不能赋值的解决方法
IE6-IE9中tbody的innerHTML不能赋值,重现代码如下 复制代码 代码如下: <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title>IE6-IE9中tbody的innerHTML不能复制bug</title> </head> <body style="height:3...2014-06-07- centos6.2,停止mysqld然后修改/etc/my.cnf datadir的位置,启动mysqld提示FAILED,查看日志 复制代码 代码如下: 120609 11:31:31 mysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended 120609 11:35:12 my...2015-03-15
Photoshop提示“此产品的许可证已过期"及“无法开始您的Adobe Photoshop CS5.1 订阅”解决方法
首先不要鄙视我用Photoshop盗版,实在是贵。现在我们来看看如果你的Photoshop提示“此产品的许可证已过期",还有“无法开始您的Adobe Photoshop CS5.1 订阅”如何解决吧...2016-09-14- 小米手机如果想要刷机就必须要先解锁验证才可以,那么,如果遇到小米解锁验证失败以及小米解锁工具登录失败的现象怎么办呢?对此,本文就为大家进行解答,有需要的朋友来看看。...2016-12-21
- 今天小编在这里就来给各位photoshop的这一款软件的使用者们来详细的说一下软件的字体出现了乱码这一问题的解决方法,那么各位有出现这个问题的,下面就来跟着小编一起看...2016-09-14
- 有部分小伙伴表示自己遇到了51模拟器程序不能打开的情况,那么51模拟器打不开怎么回事?下面我就来为大家分享一下解决的方法,有需要的小伙伴就来看一看吧。  &...2017-07-06
CentOS下php使用127.0.0.1不能连接mysql的解决方法
php代码很简单:复制代码 代码如下: $server="127.0.0.1"; println("Begin"); $link = mysql_connect($server,"mysql","mysql"); if (!$link) { die('Could not connect: ' . mysql_error().mysql_errno()); } lin...2015-03-15mysql too many open connections问题解决方法
曾经以为在my.cnf写入max_connections = 2000就可以改变mysql的最大并发量,今天查到一个命令,发现服务器的mysql最大连接数为151.控制台,连接上mysql复制代码 代码如下:show variables;这条命令可以看到所有基础配置如果...2014-05-31PHP is_subclass_of函数的一个BUG和解决方法
is_subclass_of的作用:复制代码 代码如下:bool is_subclass_of ( object object, string class_name )如果对象 object 所属类是类 class_name 的子类,则返回 TRUE,否则返回 FALSE。注: 自 PHP 5.0.3 起也可以用一个字符...2014-06-07mysql报错:MySQL server version for the right syntax to use near type=InnoDB的解决方法
这篇文章主要介绍了mysql报错:MySQL server version for the right syntax to use near type=InnoDB的解决方法,涉及MySQL语句的使用技巧,需要的朋友可以参考下...2016-01-15Can't connect to MySQL server on 'localhost' (10048)问题解决方法
解决Can't connect to MySQL server on 'localhost' (10048), 一般见于使用mysql的windows 2003服务器. 错误的出现的原因: 应用程序需要快速释放和创建新连接, 但是由于 TIME_WAIT 中存在的连接超过默认值,导致较...2013-10-04- PHPMailer在SAE上无法发送邮件怎么回事呢,我们以前在php5.2.7版本中使用了PHPMailer是可以发,但移到sae中发现无法发邮件了,那么此问题如何解决 在SAE上直接用5.2.7...2016-11-25
帝国CMS登录后台提示"您的Cookie没有开启,不能登陆成功"的解决方法
如果没有动过文件特别是/e/config/config.php文件的话!请按照如下操作肯定就OK了! 到你的主机或者服务器环境里找到php.ini文件(如果不知道在哪联系你的空间商就行了) 找到如下...2016-05-19