c# in depth 之泛型实参的类型推断
调用泛型方法时,指定类型实参常常会显得很多余。为简化工作,c#2编译器被赋予了一定的“智能”,让你在调用方法时,不需要显式声明类型实参。
在深入讨论这个主题之前,必须强调一下:类型推断只适用于泛型方法,不适用于泛型类型。
例子:static List<T> MakeList<T>(T first,T second)
...
List<String> list=MakeList<string>("Line1","Line2");
方法中的每个参数都声明为类型T。即使拿掉方法中调用表达式的<string>部分,也很容易看出在调用方法时,为T使用的类型实参是string。编译器允许将其省略,变成:
List<string> list=MakeList("Line2","Line2");
使用类型推断并非总是意味着增加了可读性。某些情况下会造成读者更难判断你要使用什么类型实参-即使编译器能轻松地判断出来。建议具体情况具体分析。在推断可用的时候,让编译器推断类型实参,多数情况下都没有问题。
注意,编译器之所以能够确定我们要将string作为类型实参使用,是因为对list的赋值也在起作用,它也指定了并且必须指定类型实参。然而,假如编译器推断错了你想要使用的类型实参,你仍可能得到一个编译错误。
编译器为什么会弄错呢?假定实际想用object作为类型实参。我们传递的方法实参仍是有效的,编译器认为我们想要的是string,因为传递的两个参数都是字符串。修改其中一个实参,把它显示转换为object,类型推断就会失败。因为一个方法实参指出T应该是string,另一个指出T应该是一个object。此时,编译器会考虑这种情况并且告知用户将T设为object能满足一切情况,将T设为string则不能。但是,在c#语言规范中,只提供了有限的推断步骤。其基本步骤如下:
1.针对每一个方法实参(普通圆括号中的参数,而不是尖括号中的),都尝试推断出泛型方法的一些类型实参。这一步是相当简单的技术
2.验证步骤一的所有结果都是一致的—换言之,假如从一个方法实参中推断出了某类型参数的类型实参,但根据另外一个类型实参推断出同一个类型参数具有另一个类型实参,则此次方法调用的推断失败。
3.验证泛型方法需要的所有类型实参都已被推断出来,不能让编译器推断一部分,自己显式指定另一部分。要么全部推断,要么全部指定。
类型推断可以结合基于类型参数数量的类型名称重载的想法,来简化泛型类型的使用。
程序清单:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace 类型推断
{
class Program
{
public static List<T> MakeList<T>(T f, T s)
{
List<T> list = new List<T>();
list.Add(f);
list.Add(s);
return list;
}
static void Main(string[] args)
{
List<object> list = MakeList("", (object)"");
foreach (string s in list)
{
Console.WriteLine(s);
}
}
}
}
运行结果:
试验知:类型推断中,如果类型如object,至少要强制转换类型实参中的一个参数,否则推断失败。
c# in depth 之泛型实参的类型推断的更多相关文章
- Java 8新特性探究(三)泛型的目标类型推断
简单理解泛型 泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数.通俗点将就是"类型的变量".这种类型变量可以用在类.接口和方法 ...
- [Effective Modern C++] Item 1. Understand template type deduction - 了解模板类型推断
条款一 了解模板类型推断 基本情况 首先定义函数模板和函数调用的形式如下,在编译期间,编译器推断T和ParamType的类型,两者基本不相同,因为ParamType常常包含const.引用等修饰符 t ...
- Java 10 实战第 1 篇:局部变量类型推断
现在 Java 9 被遗弃了直接升级到了 Java 10,之前也发过 Java 10 新特性的文章,现在是开始实战 Java 10 的时候了. 今天要实战的是 Java 10 中最重要的特性:局部变量 ...
- <T>泛型,广泛的类型
其实早在1999年的JSR 14规范中就提到了泛型概念,知道jdk5泛型的使用才正式发布,在jdk7后,又对泛型做了优化,泛型的推断. 泛型类 public class Pair<T> { ...
- 泛型T的类型获取
T.getClass()或者T.class都是非法的,因为T是泛型变量. 由于一个类的类型是什么是在编译期处理的,故不能在运行时直接在Base里得到T的实际类型. /** * 可以在service层直 ...
- 使用C#反射中的MakeGenericType函数,来为泛型方法和泛型类指定(泛型的)类型
C#反射中的MakeGenericType函数可以用来指定泛型方法和泛型类的具体类型,方法如下面代码所示这里就不多讲了,详情看下面代码一切就清楚了: using System; using Syste ...
- Java泛型-内部原理: 类型擦除以及类型擦除带来的问题
一:Java泛型的实现方法:类型擦除 大家都知道,Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,正确理解泛型概念的首要前提是理解类型擦除.Java的泛型基本上都是在编译 ...
- C# 泛型多种参数类型与多重约束 示例
C# 泛型多种参数类型与多重约束 示例 interface IMyInterface { } class Dictionary<TKey, TVal> where TKey : IComp ...
- Gson通过借助TypeToken获取泛型参数的类型的方法
最近在使用Google的Gson包进行Json和Java对象之间的转化,对于包含泛型的类的序列化和反序列化Gson也提供了很好的支持,感觉有点意思,就花时间研究了一下. 由于Java泛型的实现机制,使 ...
随机推荐
- 【转载】CentOS日志系统组成详解
日志系统有三部分组成:一.使用什么工具记录系统产生的日志信息? syslog服务脚本管理的两个进程: syslogd.klogd 来记录系统产生的日志信息: klogd 进 ...
- Eclipse 和 MyEclipse控制台console不停的自动跳动,跳出来解决方案
有时候Eclipse启动,控制台console不会自动跳出来,需要手工点击该选项卡才行,按下面的设置,可以让它自动跳出来(或不跳出来):由二种方法: 一.windows -> prefer ...
- char、signed char 和 unsigned char 的区别
ANSI C 提供了3种字符类型,分别是char.signed char.unsigned char.而不是像short.int一样只有两种(int默认就是signed int). 三者都占1个字节( ...
- 虚拟主机的配置、DNS重定向网站
虚拟主机的配置:我用的是localhost本地测试站点+Apache环境 第一步:找到Apache安装目录下的httpd-vhosts.conf文件,然后启用这个文件,如何启用这个文件呢?当然是在ht ...
- 关于运行robotium提示连接不上jar问题
robotium运行测试helloworld报错: java.lang.NoClassDefFoundError: com.jayway.android.robotium.solo.Solo at c ...
- PHP - 子类使用父类的构造函数
/* * 子类使用父类中的构造方法. */ //父类方法 class Person { //父类中的构造方法 function __construct(){ echo '这是父类中的构造方法!'; } ...
- UVa 11045 My T-shirt suits me / 二分图
二分图建图 判断是否是完全匹配就行 最大流也行 #include <cstdio> #include <cstring> const int MAX = 300; int a[ ...
- MVCC浅析(转)
在并发读写数据库时,读操作可能会不一致的数据(脏读).为了避免这种情况,需要实现数据库的并发访问控制,最简单的方式就是加锁访问.由于,加锁会将读写操作串行化,所以不会出现不一致的状态.但是,读操作会被 ...
- 【HTTP】Fiddler(二) - 使用Fiddler做抓包分析
上文( http://blog.csdn.net/ohmygirl/article/details/17846199 )中已经介绍了Fiddler的原理和软件界面.本文主要针对Fiddler的抓包处理 ...
- 列举一些常见的Python HTTP服务器
要使 Python 写的程序能在 Web 上被访问,还需要搭建一个支持 Python 的 HTTP 服务器.下面列举一些常见的 Python HTTP 服务器,以及它们目前的大致发展情况,以便用户的对 ...