洪流学堂,让你快人几步!本文首发于洪流学堂微信公众号。

本文是该系列《Unity脚本运行时更新带来了什么?》的第2篇。
洪流学堂公众号回复runtime,获取本系列所有文章。

Unity2017-2018.2中的4.x运行时已经支持到C#6,Unity2018.3将支持到C# 7.2,看看C#的新特性能给代码带来什么吧。

C#4 新特性

  • Named and optional arguments:命名参数和可选参数
  • Dynamic binding:动态绑定
  • Generic co- and contravariance:泛型的协变和逆变
  • Embedded interop types (“NoPIA”):开启嵌入类型信息,增加引用COM组件程序的中立性由于在Unity中基本用不到,故本篇省略

命名参数和可选参数

由于Unity原来使用的mono编译器并不完全对应C#版本,此特性在之前的运行时中也可用。

方法现在支持具有默认值的可选参数,因此在调用这样的方法时,可以省略这些参数。

下面用一个例子举例:

class Car
{public void Accelerate(double speed, int? gear = null, bool inReverse = false){/* ... */}
}

调用Car中的方法时,需要用:

Car myCar = new Car();
myCar.Accelerate(55);

但是需要修改第三个参数时,需要用:

myCar.Accelerate(55, null, true);

第二个参数不能省略,需要手动传入它的默认值。或者给这个方法加入一个新的重载方法。但是如果有默认值的参数很多,该怎么办?

在C#4中,可以使用如下的方法:

myCar.Accelerate(55, inReverse: true);
myCar.Accelerate(55, inReverse: true, gear: null);

这个特性可以简化有可选参数方法的调用,也可以节省很多的重载方法。

dynamic关键字

C#4.0加入了dynamic关键字,可以声明dynamic类型的变量。

在3.0及之前,如果你不知道一个变量的类型,而要去调用它的一个方法,一般会用到反射:

object calc = GetCalculator();
Type calcType = calc.GetType();
object res = calcType.InvokeMember("Add",
BindingFlags.InvokeMethod, null,
new object[] { 10, 20 });
int sum = Convert.ToInt32(res);

而有了dynamic,就可以把上面的代码简化为:

dynamic calc = GetCalculator();
int sum = calc.Add(10, 20);

dynamic的实现是基于IDynamicObject接口和DynamicObject抽象类。而动态方法、属性的调用都被转为了GetMember、Invoke等方法的调用。

协变和逆变

假如你有一个类层次结构,其中包含一个 Employee 类型以及从这个 Employee 类型继承而来的 Manager 类型(毕竟经理也是员工),那么你认为以下代码会产生什么效果?

IEnumerable<Manager> ms = GetManagers();
IEnumerable<Employee> es = ms;

看起来好像应该能够将 Manager 序列当作 Employee 序列。但是在 C# 3.0 中,赋值操作将失败;编译器将提示您,没有相应的转换功能。毕竟,该版本根本不能理解 IEnumerable 的语义。

而在 C# 4.0 中,赋值操作是有效的,因为 IEnumerable 以及其他几种接口均发生了变化,这种变化是由 C# 中新增的类型参数协变支持实现的。

4.0中在声明generic的Interface及Delegate时可以加in及out关键字,如:

public interface IEnumerable<out T> : IEnumerable
{IEnumerator<T> GetEnumerator();
}public interface IEnumerator<out T> : IEnumerator
{bool MoveNext();T Current { get; }
}public interface IComparer<in T>
{public int Compare(T left, T right);
}

out关键字的意思是说IEnumerable中T只会被用在输出中,值不会被改变。这样将IEnumerable转为IEnumerable类型就是安全的。

in的意思正好相反,是说IComparer中的T只会被用在输入中,这样就可以将IComparer安全的转为IComparer类型。

前者被称为Co-Variance(协变), 后者就是Contra-Variance(逆变)。

.Net4.0中使用out/in声明的Interface:

System.Collections.Generic.IEnumerable<out T>
System.Collections.Generic.IEnumerator<out T>
System.Linq.IQueryable<out T>
System.Collections.Generic.IComparer<in T>
System.Collections.Generic.IEqualityComparer<in T>
System.IComparable<in T>

Delegate:

System.Func<in T, …, out R>
System.Action<in T, …>
System.Predicate<in T>
System.Comparison<in T>
System.EventHandler<in T>

可以很容易地总结语言特性:在您定义类型参数时可以添加 in 或 out 关键字,从而为您提供额外的自由转换。不过,还是有一些限制。

首先,这种方式仅适用于泛型接口和委托。您不能以这种方式为类或结构声明泛型参数。造成这种限制的一个简单原因是:委托很像只拥有一个方法的接口,而由于字段的存在,无论如何都不能将类看作某种形式的接口。您可以将泛型类的任何字段当作既是输入又是输出,具体取决于您是对它执行写入还是读取操作。如果这些字段涉及类型参数,则这些参数既不能协变也不能逆变。

其次,如果某个接口或委托具有协变或逆变类型参数,则只有在该接口使用(而不是其定义)中,类型参数是引用类型时,才允许对该类型执行新的转换。

小结

本文讲解了C#4的新特性中对Unity变成有影响的新特性。其中有些概念有些难理解,可以再深入地找一些例子进行强化理解。

洪流学堂公众号回复runtime,获取本系列所有文章。

把今天的内容分享给其他Unity开发者朋友,或许你能帮到他。



《郑洪智的Unity2018课》,倾尽我8年的开发经验,结合最新的Unity2018,带你从入门到精通。

[Unity脚本运行时更新]C#4新特性相关推荐

  1. [Unity脚本运行时更新]C#7新特性

    洪流学堂,让你快人几步!本文首发于洪流学堂微信公众号. 本文是该系列<Unity脚本运行时更新带来了什么?>的第5篇. 洪流学堂公众号回复runtime,获取本系列所有文章. Unity2 ...

  2. [Unity脚本运行时更新]C#6新特性

    洪流学堂,让你快人几步!本文首发于洪流学堂微信公众号. 本文是该系列<Unity脚本运行时更新带来了什么?>的第4篇. 洪流学堂公众号回复runtime,获取本系列所有文章. Unity2 ...

  3. [Unity脚本运行时更新]C#5新特性

    洪流学堂,让你快人几步!本文首发于洪流学堂微信公众号. 本文是该系列<Unity脚本运行时更新带来了什么?>的第3篇. 洪流学堂公众号回复runtime,获取本系列所有文章. Unity2 ...

  4. [Unity脚本运行时更新]C#7.3新特性

    洪流学堂,让你快人几步!本文首发于洪流学堂微信公众号. 本文是该系列<Unity脚本运行时更新带来了什么?>的第8篇. 洪流学堂公众号回复runtime,获取本系列所有文章. Unity2 ...

  5. [Unity脚本运行时更新]C#7.2新特性

    洪流学堂,让你快人几步!本文首发于洪流学堂微信公众号. 本文是该系列<Unity脚本运行时更新带来了什么?>的第7篇. 洪流学堂公众号回复runtime,获取本系列所有文章. Unity2 ...

  6. [Unity脚本运行时更新]C#7.1新特性

    洪流学堂,让你快人几步!本文首发于洪流学堂微信公众号. 本文是该系列<Unity脚本运行时更新带来了什么?>的第6篇. 洪流学堂公众号回复runtime,获取本系列所有文章. Unity2 ...

  7. Unity脚本运行时更新带来了什么?

    洪流学堂,让你快人几步!本文首发于洪流学堂微信公众号. 本文是该系列<Unity脚本运行时更新带来了什么?>的第一篇,后续会结合Unity实例介绍C# 4 - C# 6都带来了具体哪些变化 ...

  8. Unity项目运行时动态更新光照贴图 | LightMap

    Unity项目运行时动态更新烘培的光照贴图 动态更新烘培的光照贴图 场景的物件没有发生变化(也就是说没有运行时加载在场景上的Prefab) 场景的烘培贴图已经更新,但是有些物件prefab想运行时加载 ...

  9. Unity Timeline运行时脚本控制Mute和UnMute(Mute/UnMute a timeline track via scripting)

    Unity Timeline运行时脚本控制Mute和UnMute 最近遇到了一个问题就是希望能够在运行时脚本控制Timeline特定轨道的mute和unmute,本来以为是一个很简单的问题,结果发现并 ...

最新文章

  1. OC指示符assign、atomic、nonatomic、copy、retain、strong、week的解释
  2. 私有云的优缺点_2019年中国云计算行业竞争格局与发展趋势分析「图」
  3. NLP:Transformer的架构详解之详细攻略(持续更新)
  4. AI扫雷有多牛?他国纷纷来求师学艺(附完整教程)
  5. MySQL8常见客户端和启动相关参数
  6. json及JavaBean转json
  7. java arraylist排序_最全Java集合笔记
  8. “带货”的逻辑:直播电商产业链研究报告
  9. tcpdump 命令快速实用参考手册
  10. 苹果推出新款iPad Air和iPad mini,升级A12处理器
  11. 客户端和服务器之间的信息结构,客户端和服务器之间的信息结构
  12. python教学ppt百度云_python教程ppt百度云盘-Python教程ppt课件类型的
  13. ftp服务器设置登录账号密码是什么意思,局域网ftp服务器登录密码是什么
  14. 使用uboot + minicom串口协议下载镜像文件
  15. 计算机小高考成绩,2018江苏小高考成绩出来了!昆山*亮眼的学校是…
  16. 【转】D365 FO第三方集成(四)---客户端调用
  17. 如何在公众号添加视频链接
  18. 计算雅思成绩C语言,雅思成绩总分其实是这么计算的
  19. c++操作Office之Word
  20. Excel中工作表间的关联链接方法

热门文章

  1. 【Vegas原创】imp/exp导入导出数据
  2. Leanote使用mysql_《搭建个人Leanote云笔记本》阿里云体验实验室 教程
  3. 解释Linux进程的父子关系,Linux进程管理
  4. IWorkbook 引入_如果引入国内,你会买单吗?日产全新小型SUV亮相|小型suv|日产|轩逸|新车|本田|丰田...
  5. html 图片加速,35种加速网站访问的最好做法
  6. python psutil替代_Python2.7 psutil模块
  7. 设计灵感|浓浓人文感!中文活动海报设计学习案例
  8. 计算机高级技师考试题,高级技师考试题及答案.doc
  9. Build-Docker-Image-from-Zero: 从零构建Docker镜像
  10. Ramfs、rootfs 和initramfs