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

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

 //定义一个泛型方法,参数分别为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. Post-office 树状数组

    Post office 题目描述 There are N(N<=1000) villages along a straight road, numbered from 1 to N for si ...

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

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

  3. mysql force index() 强制索引的使用

    mysql force index() 强制索引的使用 之前跑了一个SQL,由于其中一个表的数据量比较大,而在条件中有破坏索引或使用了很多其他索引,就会使得sql跑的非常慢... 那我们怎么解决呢? ...

  4. [转]通过AngularJS directive对bootstrap日期控件的的简单包装

    本文转自:http://www.cnblogs.com/Benoly/p/4109460.html 最近项目上了AngularJS,而原来使用的日期控件的使用方式也需要改变,于是开始了倒腾,看了官方的 ...

  5. [麦先生]学习PDO循序渐进使用方式

    使用方式  特点一:支持跨数据库 1:首先实例化PDO,创建PDO对象的四个必备参数:host(哪一种类型的数据库,mysql/orcal/SQLserver等);dbname(数据库的名称);cha ...

  6. USACO section1.1 Broken Necklace

    /* ID: vincent63 LANG: C TASK: beads */ #include <stdio.h> #include<stdlib.h> #include&l ...

  7. Hadoop中WritableComparable 和 comparator

    1.WritableComparable 查看HadoopAPI,如图所示: WritableComparable继承自Writable和java.lang.Comparable接口,是一个Writa ...

  8. 最长上升子序列(LIS)模板

    最长递增(上升)子序列问题:在一列数中寻找一些数,这些数满足:任意两个数a[i]和a[j],若i<j,必有a[i]<a[j],这样最长的子序列称为最长递增(上升)子序列. 考虑两个数a[x ...

  9. linux之间进程通信

    进程间通信方式:                    同主机进程间数据交换机制: pipe(无名管道) / fifo(有名管道)/ message queue(消息队列)和共享内存. 必备基础: f ...

  10. 通过JDBC进行简单的增删改查(二)

    本章笔记更易理解和学习,也是我第一次初学的笔记. package javastudy; import java.sql.Connection; import java.sql.DriverManage ...