今天来结束第九章,聊下我们经常忽略,但是编译器会帮我们完成的"类型判断和重载决策",理解编译器如何帮我们完成,相信在写代码时会更明确,避免一些编译出错,排查的问题,让我们开发更给力。

  我们知道隐式类型的数组以及将方法组转换为委托类型都需要类型推断,但将方法组作为其它方法的参数进行转换时,会显得极其复杂,我们由浅入深,一步一步来看,编译器是如何帮我们做的一些推断。

 //定义一个泛型方法,参数分别为TInput类型和一个Func<TInput, TResult>类型的委托
public static TResult Get<TInput, TResult>(TInput input, Func<TInput, TResult> func)
{
return func(input);
}
static void Main(string[] args)
{
var a = Get("", x => int.Parse(x));
//第一个参数是字符串,所以可以推断TInput类型有到string类型的隐式转换
//则方法签名为:public static TResult Get<string, TResult>(string input, Func<string, TResult> func)
//第二个参数是一个Lambda表达式,根据返回的类型是一个int,所以可以推断TResult类型有到int类型的隐式转换
//则方法签名为:public static int Get<string, int>(string input, Func<string, int> func)
//根据上述的步骤,我们推断出了TInput和TResult类型
}

  返回类型集合

  从上述代码中,可以看到TResult类型是由Lambda表达式的返回值类型来推断的,那如果我有多个返回类型又是一种什么情况呢?请看下面的代码。

 var b = Get(, delegate (int x) {
if (x == )
{
return "";
}
else
{
return new object();
}
});
//由上可以推断出TInput类型有到int类型的隐式转换,则TInput为int
//而返回类型有两个,一个是string类型,一个是object类型,但是string类型有到object类型的隐式转换,则TResult为object类型
//编译器帮我们把所有的返回类型放入一个集合,对集合中的类型进行判断,判断是否有一个类型是可由剩余其它类型隐式转换可得,则把这个类型作为返回值的类型

  如何选择正确的重载

  如果重载具有二义性,那编译肯定是过不了的,要么强制转换某个参数以符合某个方法的签名,或者修改重载方法。从参数或者返回类型考虑,请参照下面一条:

  从任何类型"转换成它本身"被认为好于"转换成其它类型",如

 static void Debug0(int x) { }
static void Debug0(double x) { } Debug0(); //static void Debug0(int x)
Debug0(5.0); //static void Debug0(double x)
//int有到double的隐式转换,所以存在二义性,但根据int=>int是好于int=>double的,所以选择使用static void Debug0(int x)

  同理于返回类型,作用于委托或者Lambda表达式,如

 static int Debug1(Func<int> func) {
return func();
} static double Debug1(Func<double> func)
{
return func();
} Debug1(() => 1.1);
Debug1(delegate () { return 1.1; });
//根据Lambda表达式和匿名方法,Debug1(() => 1.1)和Debug1(delegate () { return 1.1; })返回的类型是double类型,则Lambda表达式和匿名方法转换成Func<double>类型的实例,调用的则是static double Debug1(Func<double> func)
Debug1(() => );
Debug1(delegate () { return ; });
//根据Lambda表达式和匿名方法,Debug1(() => 1)和Debug1(delegate () { return 1; })返回的类型是int类型,则Lambda表达式和匿名方法转换成Func<int>类型的实例,调用的则是static double Debug1(Func<int> func)

  请斧正。

17.C#类型判断和重载决策(九章9.4)的更多相关文章

  1. C#与Java对比学习:类型判断、类与接口继承、代码规范与编码习惯、常量定义

    类型判断符号: C#:object a;  if(a is int) { }  用 is 符号判断 Java:object a; if(a instanceof Integer) { } 用 inst ...

  2. 第17课 类型萃取(1)_基本的type_traits

    1. type_traits类型萃取 (1)type_traits通过定义一些结构体或类,并利用模板类特化和偏特化的能力,给类型赋予一些特性,这些特性根据类型的不同而异.在程序设计中可以使用这些tra ...

  3. python的数据结构分类,以及数字的处理函数,类型判断

    python的数据结构分类: 数值型 int:python3中都是长整形,没有大小限制,受限内存区域的大小 float:只有双精度型 complex:实数和虚数部分都是浮点型,1+1.2J bool: ...

  4. JS类型判断typeof PK {}.toString.call(obj)

    参考链接:https://www.talkingcoder.com/article/6333557442705696719 先看typeof <!doctype html> <htm ...

  5. Lambda03 方法引用、类型判断、变量引用

    1 方法引用 1.1 方法引用的好处 方法引用结合 Lambda 可以引用已存在的方法,省略很多编码,而且可读性更强,它可以自动装配参数与返回值. 在编写lambda表达式的时候可以通过方法引用的方式 ...

  6. Swift4 类与继承, 类型转换, 类型判断

    创建: 2018/03/05 完成: 2018/03/07 更新: 2018/03/09 完善标题 [Swift4 类与继承, 类型转换] -> [Swift4 类与继承, 类型转换与判断] 补 ...

  7. C#保留2位小数几种场景总结 游标遍历所有数据库循环执行修改数据库的sql命令 原生js轮盘抽奖实例分析(幸运大转盘抽奖) javascript中的typeof和类型判断

    C#保留2位小数几种场景总结   场景1: C#保留2位小数,.ToString("f2")确实可以,但是如果这个数字本来就小数点后面三位比如1.253,那么转化之后就会变成1.2 ...

  8. 【C/C++开发】C++11的模板类型判断——std::is_same和std::decay

    C++11的模板类型判断--std::is_same和std::decay 问题提出:有一个模板函数,函数在处理int型和double型时需要进行特殊的处理,那么怎么在编译期知道传入的参数的数据类型是 ...

  9. 20190908 On Java8 第十九章 类型信息

    第十九章 类型信息 RTTI(RunTime Type Information,运行时类型信息)能够在程序运行时发现和使用类型信息. Java 主要有两种方式在运行时识别对象和类信息: "传 ...

随机推荐

  1. R语言画图布局摆放(layout)

    require(ggplot2) require(Cairo) require(grid) p = ggplot(iris,aes(x = Species,y = Sepal.Length,colou ...

  2. BI测试工具之跨数据库数据对比,支持oracle,sqlserver

    应用场景: 本周在进行SIT,我帮助仅有的一个测试妹妹对部分表进行数据质量验证,第一步需要做的就是比对source与stage表的table definition 与 数据内容的一致性. 本项目使用的 ...

  3. LeetCode题目分类

    利用堆栈:http://oj.leetcode.com/problems/evaluate-reverse-polish-notation/http://oj.leetcode.com/problem ...

  4. Vim tips

    1.光标移动: (1).NG -> 移动到第N行,或者使用:N (2).gg -> 移动到第一行 (3).G -> 移动到最后一行 (4).单词移动: w -> 移动到下一个单 ...

  5. C语言异或运算在程序设计中的妙用

    异或运算符∧也称XOR运算符.它的规则是若参加运算的两个二进位同号,则结果为0(假):异号则为1(真).即0∧0=0,0∧1=1,1∧1=0. 性质: (1).与1异或会翻转 (2).与0异或保持不变 ...

  6. 第20章 DLL高级技术(2)

    20.3 延迟载入DLL 20.3.1延迟载入的目的 (1)如果应用程序使用了多个DLL,那么它的初始化可能比慢,因为加载程序要将所有必需的DLL映射到进程的地址空间.→利用延迟加载可将载入过程延伸到 ...

  7. Linux命令学习-grep

    1.作用Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expression Print,表示全局 ...

  8. LoadRunner 11 完整卸载

    实现彻底删除LR的步骤 打开任务管理器,关闭所有LR相关的进程 请备份好所有LR脚本 进入控制面板-添加与删除,找到HP LoadRunner并点击删除按钮,若出现提示“shared DLLs”消息框 ...

  9. web安全测试工具的局限性

    讨论安全漏洞的原理,谈谈工具的局限. 先说下扫描工具的原理: 扫描工具可以看做由两部分组成:爬虫+校验机构.爬虫的作用是搜集整个被采集对象的链接,然后校验机构对这些链接逐一进行验证. 说扫描工具的局限 ...

  10. python基础随笔

    一: 作用域 对于变量的作用域,只要内存中存在,该变量就可以使用. 二:三元运算 name = 值1 if 条件 else 值2 如果条件为真:result = 值1 如果条件为假:result = ...