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泛型的实现机制,使 ...
随机推荐
- BZOJ 1704: [Usaco2007 Mar]Face The Right Way 自动转身机( 贪心 )
贪心...先枚举k, 然后从左往右扫一遍, 发现位置p的牛的状态不符合就将 [p, p + k ) 的牛都转身, 假如p + k - 1 已经超过了最右边牛的位置那这个k就不符合要求. 符合要求的就可 ...
- 转:携程App的网络性能优化实践
http://kb.cnblogs.com/page/519824/ 携程App的网络性能优化实践 受益匪浅的一篇文章,让我知道网络交互并不是简单的传输和接受数据.真正的难点在于后面的性能优化 下面对 ...
- cocos2dx 在windows上实现键盘输入
cocos2d主要面向的是触摸屏幕设备的,在WINDOWS下的定位感觉多多少少就是相当于一个模拟器,因此并没有太多的PC下重要的键盘支持.然而响应键盘消息对于调试来说可以提供不少方便.下边就通过更改c ...
- C++能在三个地方创造对象,而Delphi只有一个地方
C++能在堆栈.堆.资料区创造对象. 但是Delphi只能在堆上创造对象
- bottle-session 0.3 : Python Package Index
bottle-session 0.3 : Python Package Index bottle-session 0.3
- addEventListener()及attachEvent()区别分析
Javascript 的addEventListener()及attachEvent()区别分析 Mozilla中: addEventListener的使用方式: target.addEventLis ...
- codeforces 148D 概率DP
题意: 原来袋子里有w仅仅白鼠和b仅仅黑鼠 龙和王妃轮流从袋子里抓老鼠. 谁先抓到白色老师谁就赢. 王妃每次抓一仅仅老鼠,龙每次抓完一仅仅老鼠之后会有一仅仅老鼠跑出来. 每次抓老鼠和跑出来的老鼠都是随 ...
- Eclipse用法和技巧一:还原视图和编辑器
链接地址:http://blog.csdn.net/maybe_windleave/article/details/8763744 在实际使用eclipse过程中,由于经常关闭或者打开视图,某一刻你会 ...
- 将Qt 动态链接生成的exe及依赖dll打包方法
源地址:http://blog.csdn.net/ztz0223/article/details/8939341 将Qt 动态链接生成的exe及依赖dll打包方法 原文:http://www.qtcn ...
- Delphi - 闲来无事,自己写个Timer玩玩(多线程Timer)
明天去坐火车,回家,今天就没有事做,本来在弄一个跨进程获取其他程序里面组件,如ListView,ListBox,Button等的信息,突然有个想法自己写个Timer,不用SetTimer函数,我们自己 ...