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

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

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

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

C#6 新特性

String填空

String.Format 非常常用,但使用起来很麻烦而且容易出错。在格式字符串中需要使用类似{0}的占位符,还得单独提供对应的参数:

var s = String.Format("{0} is {1} year{{s}} old", p.Name, p.Age);

字符串填空可以让你直接将表达式放在字符串的“空”中,就是在最前面加上$

var s = $"{p.Name} is {p.Age} year{{s}} old";

String.Format类似,可选的对齐和格式都可以指定:

var s = $"{p.Name,20} is {p.Age:D3} year{{s}} old";

填空的内容可以是任何表达式:

var s = $"{p.Name} is {p.Age} year{(p.Age == 1 ? "" : "s")} old";

请注意,条件表达式是在括号里,因此:"s"不会与格式说明符混淆。

自动属性的增强

自动属性的初始化

现在可以给自动属性赋初始值了。

public class Customer
{
    public string First { get; set; } = "Jane";
    public string Last { get; set; } = "Doe";
}

这个初始化直接赋值给属性的后备字段(自动生成的隐藏字段),并没有通过set方法。初始化的时机和字段初始化的时机一致。

和字段初始化一致,自动属性初始化时无法引用this,毕竟初始化是在对象完全初始化之前进行的。

自动属性可以只设置Get

自动属性现在可以只设置Get,不设置Set

public class Customer
{
    public string First { get; } = "Jane";
    public string Last { get; } = "Doe";
}

只有Get方法的自动属性的后备字段被隐式声明为readonly(尽管仅用于反射)。这个属性可以在属性声明时直接初始化,就像上面代码一样。也可以在类的构造函数中初始化,会直接赋值给后备字段。

public class Customer
{
    public string Name { get; }
    public Customer(string first, string last)
    {
        Name = first + " " + last;
    }
}

表达式化的方法体

现在Lambda表达式可以用于成员方法的方法体。

表达式化的成员方法

方法、运算符可以用lambda的箭头来定义表达式主体。

public Point Move(int dx, int dy) => new Point(x + dx, y + dy); 
public static Complex operator +(Complex a, Complex b) => a.Add(b);
public static implicit operator string(Person p) => p.First + " " + p.Last;

效果与带有单个return语句的块代码完全相同。

对于返回void的方法以及返回Task的异步方法,箭头语法仍然适用,但箭头后面的表达式必须是语句表达式(就像lambdas的规则一样):

public void Print() => Debug.Log(First + " " + Last);

表达式化的成员属性

属性和索引器可以有getter和setter。表达式主体可用于编写只有getter的属性和索引器,其中getter的主体由表达式主体提供:

public string Name => First + " " + Last;
public Customer this[long id] => store.LookupCustomer(id); 

注意这里没有get关键字。

Using static

该功能允许导入类型的所有可访问的静态成员,使其在后续代码中无需使用类型限定符即可使用:

using UnityEngine;
using static UnityEngine.Debug;
using static UnityEngine.Mathf;

class CS6Updates : MonoBehaviour
{
    void Start()
    {
        Log(Sqrt(3 * 3 + 4 * 4));
    }
}

如果你经常需要使用一些静态方法时,这个新功能就很棒,可以减少很多的代码量。如上面代码中本来应该写Debug.LogMathf.Sqrt

扩展方法

扩展方法是静态方法,但使用的时候是实例方法。using static不会将扩展方法引入到全局范围内,还是需要通过实例方法去调用。

using static System.Linq.Enumerable; // 具体类型,不是命名空间
class Program
{
    static void Main()
    {
        var range = Range(5, 17);                // Ok: not extension
        var odd = Where(range, i => i % 2 == 1); // Error, not in scope
        var even = range.Where(i => i % 2 == 0); // Ok
    }
}

Null条件运算符

有时候代码中会充斥着null检查。null条件运算符可以让你仅在对象非null的情况下访问对象成员,否则返回null。

int? length = customers?.Length; // null if customers is null
Customer first = customers?[0];  // null if customers is null

null条件运算符经常和空接合运算符??一起使用:

int length = customers?.Length ?? 0; // 0 if customers is null

null条件运算符采用就近原则,我们先看一下以下的代码:

int? first = customers?[0].Orders.Count();

上面的代码等价于(除了 customers 只会计算一次):

int? first = (customers != null) ? customers[0].Orders.Count() : null;

null条件运算符可以链式计算:

int? first = customers?[0].Orders?.Count();

注意调用带括号的委托类型变量时不能直接使用 ? ,这会导致很多语法歧义。你可以使用Invoke调用:

if (predicate?.Invoke(e) ?? false) { … }

触发事件时建议这么调用:

PropertyChanged?.Invoke(this, args);

在触发事件之前,这是一种检查null的简单且线程安全的方法。它是线程安全的原因是该功能仅计算左侧一次,并将其保存在临时变量中。

nameof表达式

有些时候你可能想知道一个变量的变量名是什么。

使用字符串可以达到这个目的,但是容易出错。nameof表达式本质上是一种奇特的字符串文字,其中编译器检查你是否具有给定名称的内容,并且Visual Studio知道它引用的内容,因此导航和重构起作用。

if (x == null) throw new ArgumentNullException(nameof(x));
WriteLine(nameof(person.Address.ZipCode)); // prints "ZipCode"

索引初始化

对象和集合初始化对于初始化对象的字段、属性或为集合提供一组初始数据非常有用。但使用索引初始化字典和其他对象不太优雅。对象初始化现在可以使用一个新语法,可以通过索引将值设置为Key。

var numbers = new Dictionary<int, string> {
    [7] = "seven",
    [9] = "nine",
    [13] = "thirteen"
};

异常过滤器

try { … }
catch (MyException e) when (myfilter(e))
{
    …
}

如果括号内表达式的计算结果为true,则运行catch块,否则异常将不被catch。

异常过滤器比捕获和重新抛出更好用,因为它可以保持堆栈不受破坏。如果稍后的异常导致堆栈被转储,你可以看到它最初来自哪里,而不仅仅是它重新抛出的最后一个位置。

“滥用”异常过滤器也是常见且被接受的一种方式:例如日志记录。他们可以在不拦截异常的情况下检查“飞过”的异常。在这些情况下,过滤器通常会调用一个错误返回的辅助函数来执行:

private static bool Log(Exception e) { /* log it */ ; return false; }
…
try { … } catch (Exception e) when (Log(e)) {}

catch和finally中的异步

Resource res = null;
try
{
    res = await Resource.OpenAsync(…);       // You could do this.
    …
} 
catch(ResourceException e)
{
    await Resource.LogAsync(res, e);         // Now you can do this …
}
finally
{
    if (res != null) await res.CloseAsync(); // … and this.
}

小结

本文讲解了C#6的新特性中对Unity编程有影响的新特性。

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容

  • 睿宝读易经四十四十一卦一遍,累计第二遍,妈妈通读易经54遍。 早上由我送两宝去洋村幼儿园。跟蒋园长商量说两个小朋友...
    娟娟_52c0阅读 94评论 0 0
  • 今天下午放学后,来到家里,老公正忙着在厨房做晚饭,儿子放下书包就开始写作业,我也随手拿起手机练起字来。一会儿功夫,...
    小拓拓阅读 285评论 0 2
  • 猛地睁开眼,已经七点钟了。迅速洗簌完毕,便向学校奔去。每天早上七点十五至七点四十,是学生们跑操的时间。 站在操场中...
    树海云天阅读 327评论 3 2