C#6中的新增功能 【Unity3D亲测】
随着Unity2017的普及,使用.NET 4X的开发者也越来越多了,下面笔者给大家介绍一下在C# 6中的新功能主要是怕自己忘记,2333,有些功能还是很实用的~
使用Unity版本2018.2.9f1
有说错或者不准确的地方欢迎大家留言指正
参考资料:
自动属性增强功能
#region 常规
public string FirstName0 { get; private set; }
public string LastName0 { get; private set; }
public readonly string FirstName1 = "菜鸟";
public readonly string LastName1 = "海澜";
#endregion
#region 自动属性增强功能
public string FirstName2 { get; }
public string LastName2 { get; }
public CSharpSix()
{
FirstName2 = "菜鸟";
LastName2 = "海澜";
}
public CSharpSix(string firstName, string lastName)
{
if (string.IsNullOrWhiteSpace(lastName))
throw new ArgumentException(message: "不能是空白", paramName: nameof(lastName));
FirstName2 = firstName;
LastName2 = lastName;
}
public void ChangeName(string newLastName)
{
//LastName2 = newLastName;//报错,因为属性只读
}
#endregion
自动属性初始值设定项
#region 自动属性初始值设定项
public string FirstName3 { get; } = "菜鸟";
public string LastName3 { get; } = "海澜";
#endregion
Expression-bodied 函数成员 这适用于方法和只读属性
#region Expression-bodied 函数成员 这适用于方法和只读属性
//还可以在只读属性中使用 expression-bodied 成员:
public string FullName => $"{FirstName1} {LastName1}";
//等同于
public readonly string FullName1 = "菜鸟海澜";
//仅限一条可以表示为表达式的语句
public override string ToString() => $"{FirstName1}, {LastName1}";
public void LogMessage(string a, string b) => Debug.Log(a + b);
#endregion
using static
增强功能可用于导入单个类的静态方法。 以前,using 语句将所有类型导入命名空间中
下面的示例中IsNullOrWhiteSpace可直接调用
#region using static
//using static 增强功能可用于导入单个类的静态方法。 以前,using 语句将所有类型导入命名空间中
public void TestUsingStatic(string lastName)
{
//使用 using static
if (IsNullOrWhiteSpace(lastName))
{
throw new ArgumentException(message: "Cannot be blank", paramName: nameof(lastName));
}
//原有方式
if (string.IsNullOrWhiteSpace(lastName))
{
throw new ArgumentException(message: "Cannot be blank", paramName: nameof(lastName));
}
}
#endregion
可空类型(Nullable)与 Null 条件运算符
示例1
int? nullIntOne = 3;
//等同于
Nullable<int> nullInt_One = new Nullable<int>(3);
double? num3 = new double?();
bool? boolval = new bool?();
int Number_Default; //默认值0
public int? number_Null;//默认值null
如果number_Null 为null则打印666
Debug.Log(cSharpSix.number_Null ?? 666);
如果打印则报错:NullReferenceException: Object reference not set to an instance of an object
cSharpSix = null;
//报错:NullReferenceException: Object reference not set to an instance of an object
Debug.Log(cSharpSix.FirstName2);
使用Null 条件运算符不会报错,会打印Null
其中的 【?.】可以分别理解为【?】如果不为Null 【.】就执行
//不会报错,打印Null 其中的 【?.】可以分别理解为【?】如果不为Null 【.】就执行
Debug.Log(cSharpSix?.FirstName2);
在委托时的使用
public Action actionOne;
public void Test()
{
actionOne += CustomAction;
actionOne?.Invoke();
//等同于
if (actionOne != null)
{
actionOne();
}
}
public void CustomAction()
{
Debug.Log("123");
}
当然也可以这么写,不过笔者认为这种写法还是少用为好,因为
- 可读性低,大量使用对其他阅读者将是灾难
//灾难
Debug.Log(cSharpSix?.FirstName2==null ? cSharpSix.number_Null?.ToString() : "三元运算菜鸟海澜");
Debug.Log(cSharpSix?.number_Null?.ToString()??"defualt菜鸟海澜");
而且在文档中对应委托使用Null 条件运算符有这样的描述
这个缓存结果笔者有些不解,难道是让他具有原子性?有知道的大佬可以给我留言,不胜感谢~
字符串内插
可读性提高
public void LogMessage()
{
Debug.Log($"姓{FirstName3}名{LastName3}");
Debug.LogFormat("姓:{0}名:{1}", FirstName3, LastName3);
}
也可对字符串使用【:】设置格式
还有一些详细的设置,可参考:$ - 字符串内插
public void LogDateTime()
{
Debug.Log($"现在的时间为{DateTime.Now}");
Debug.Log($"现在的时间为{DateTime.Now:yyyy-MM-dd hh:mm:ss}");
}
异常筛选器
如果用于异常筛选器的表达式计算结果为 true,则 catch 子句将对异常执行正常处理。 如果表达式计算结果为 false,则将跳过 catch 子句,直接抛出异常。
老版本写法
public void CatchException()
{
try
{
throw new Exception("海澜1");
}
catch (Exception ex)
{
if (ex.Message == "海澜0")
{
Debug.LogWarning("异常0");
}
if (ex.Message == "海澜1")
{
Debug.LogWarning("异常01");
}
}
}
新版本写法
public void CatchExceptionWhen()
{
try
{
throw new Exception("海澜1");
}
catch (Exception ex) when (ex.Message == "海澜0")
{
Debug.LogWarning("异常0");
}
catch (Exception ex) when(ex.Message == "海澜1")
{
Debug.LogWarning("异常1");
}
}
优点:使用这个when可以更好的判断一个错误是继续处理还是重新抛出去。按照以前的做法,在catch块内如需再次抛出去,需要重新throw出去,这时的错误源是捕捉后在抛的,而不是原先的,有了when语法就可以直接定位到错误源。
使用异常筛选器的另一种推荐模式是将其用于日志记录例程。 这种用法还会利用当异常筛选器计算结果为 false 时,保留异常引发点的方式。
日志记录方法将是这样一种方法:其参数为无条件返回 false 的异常:
public void CatchExceptionWhenWithLog()
{
try
{
throw new Exception("海澜1");
}
catch (Exception ex) when (LogException(ex.Message))
{
}
catch (Exception ex) when (ex.Message == "海澜0")
{
Debug.LogWarning("异常0");
}
catch (Exception ex) when (ex.Message == "海澜1")
{
Debug.LogWarning("异常1");
}
}
public bool LogException(string ex)
{
Debug.LogWarning($"记录异常信息{ex}");
return false;
}
nameof 表达式
public void TestNameOf(string firstName)
{
Debug.Log($"输出{firstName}");
Debug.Log($"输出{nameof(firstName)}");
Debug.Log($"输出{nameof(CSharpSix.staticName)}");
}
打印信息
Catch 和 Finally 块中的 Await
在 catch 和 finally 子句中添加 await 支持的实现细节可确保该行为与同步代码的行为一致
public async Task TestAwait()
{
try
{
throw new Exception("菜鸟海澜");
}
catch(Exception ex) when (ex.Message.Contains("海澜"))
{
await LogExceptionAsync();
}
finally
{
await CloseConnectionAsync();
}
}
private Task CloseConnectionAsync()
{
Debug.Log("CloseConnectionAsync");
Thread.Sleep(1000);
return null;
}
private Task LogExceptionAsync()
{
Debug.Log("LogExceptionAsync");
Thread.Sleep(1000);
return null;
}
索引初始值设定项
笔者现在用的这个版本会报错
#region 索引初始值设定项
private Dictionary<int, string> webErrors = new Dictionary<int, string>
{
[404] = "Page not Found",
[302] = "Page moved, but left a forwarding address.",
[500] = "The web server can't come out to play today."
};
#endregion
但是放在方法中不会,估计官方会在后续版本中修复
public void aaa()
{
Dictionary<int,string> webErrors = new Dictionary<int, string>
{
[404] = "Page not Found",
[302] = "Page moved, but left a forwarding address.",
[500] = "The web server can't come out to play today."
};
}
改进了重载解析
现在可以正确的区分 Task.Run(Action) 和 Task.Run(Func<Task>())。
#region 改进了重载解析
public static Task<int> DoThings()
{
return Task.FromResult(666);
}
#endregion
Task<int> result = CSharpSix.DoThings();
Debug.Log($"结果为{result.Result}");
集合初始值设定项中的扩展 Add 方法
这个感兴趣的同学可以自行查看,不过笔者没发现他的特别便利之处
下面是笔者测试时所有的示例代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Threading.Tasks;
public class TestCSharpSix : MonoBehaviour
{
void Start()
{
var cSharpSix = new CSharpSix();
Debug.Log(cSharpSix.number_Null ?? 666);
cSharpSix = null;
//报错:NullReferenceException: Object reference not set to an instance of an object
//Debug.Log(cSharpSix.FirstName2);
//不会报错,打印Null 其中的 【?.】可以分别理解为【?】如果不为Null 【.】就执行
Debug.Log(cSharpSix?.FirstName2);
Debug.Log(cSharpSix?.FirstName2 ?? "自定义菜鸟海澜");
Debug.Log(cSharpSix?.FirstName2 ?? "自定义菜鸟海澜");
cSharpSix = new CSharpSix();
//灾难
Debug.Log(cSharpSix?.FirstName2 == null ? cSharpSix.number_Null?.ToString() : "三元运算菜鸟海澜");
Debug.Log(cSharpSix?.number_Null?.ToString() ?? "defualt菜鸟海澜");
cSharpSix.LogMessage();
cSharpSix.CatchException();
cSharpSix.CatchExceptionWhen();
cSharpSix.CatchExceptionWhenWithLog();
cSharpSix.TestNameOf("菜鸟海澜");
Task.Run(() => { cSharpSix.TestAwait(); });
Task<int> result = CSharpSix.DoThings();
Debug.Log($"结果为{result.Result}");
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using static System.String;
using static System.Linq.Enumerable;
using System.Threading.Tasks;
using System.Threading;
public class CSharpSix
{
#region 常规
public string FirstName0 { get; private set; }
public string LastName0 { get; private set; }
public readonly string FirstName1 = "菜鸟";
public readonly string LastName1 = "海澜";
#endregion
#region 自动属性增强功能
public string FirstName2 { get; }
public string LastName2 { get; }
public CSharpSix()
{
FirstName2 = "菜鸟";
LastName2 = "海澜";
}
public CSharpSix(string firstName, string lastName)
{
if (string.IsNullOrWhiteSpace(lastName))
throw new ArgumentException(message: "不能是空白", paramName: nameof(lastName));
FirstName2 = firstName;
LastName2 = lastName;
}
public void ChangeName(string newLastName)
{
//LastName2 = newLastName;//报错,因为属性只读
}
#endregion
#region 自动属性初始值设定项
public string FirstName3 { get; } = "菜鸟";
public string LastName3 { get; } = "海澜";
#endregion
#region Expression-bodied 函数成员 这适用于方法和只读属性
//还可以在只读属性中使用 expression-bodied 成员:
public string FullName => $"{FirstName1} {LastName1}";
//等同于
public readonly string FullName1 = "菜鸟海澜";
//仅限一条可以表示为表达式的语句
public override string ToString() => $"{FirstName1}, {LastName1}";
public void LogMessage(string a, string b) => Debug.Log(a + b);
#endregion
#region using static
//using static 增强功能可用于导入单个类的静态方法。 以前,using 语句将所有类型导入命名空间中
public void TestUsingStatic(string lastName)
{
//使用 using static
if (IsNullOrWhiteSpace(lastName))
{
throw new ArgumentException(message: "Cannot be blank", paramName: nameof(lastName));
}
//原有方式
if (string.IsNullOrWhiteSpace(lastName))
{
throw new ArgumentException(message: "Cannot be blank", paramName: nameof(lastName));
}
}
#endregion
#region 可空类型
int? nullIntOne = 3;
//等同于
Nullable<int> nullInt_One = new Nullable<int>(3);
double? num3 = new double?();
bool? boolval = new bool?();
int Number_Default; //默认值0
public int? number_Null;//默认值null
public Action actionOne;
public void Test()
{
actionOne += CustomAction;
actionOne?.Invoke();
//等同于
if (actionOne != null)
{
actionOne();
}
Debug.Log("注册成功");
}
public void CustomAction()
{
Debug.Log("123");
}
#endregion
#region 字符串内插
public void LogMessage()
{
Debug.Log($"姓{FirstName3}名{LastName3}");
Debug.LogFormat("姓:{0}名:{1}", FirstName3, LastName3);
}
public void LogDateTime()
{
Debug.Log($"现在的时间为{DateTime.Now}");
Debug.Log($"现在的时间为{DateTime.Now:yyyy-MM-dd hh:mm:ss}");
}
#endregion
#region 异常筛选器
public void CatchException()
{
try
{
throw new Exception("海澜1");
}
catch (Exception ex)
{
if (ex.Message == "海澜0")
{
Debug.LogWarning("异常0");
}
if (ex.Message == "海澜1")
{
Debug.LogWarning("异常01");
}
}
}
public void CatchExceptionWhen()
{
try
{
throw new Exception("海澜1");
}
catch (Exception ex) when (ex.Message == "海澜0")
{
Debug.LogWarning("异常0");
}
catch (Exception ex) when (ex.Message == "海澜1")
{
Debug.LogWarning("异常1");
}
}
public void CatchExceptionWhenWithLog()
{
try
{
throw new Exception("海澜1");
}
catch (Exception ex) when (LogException(ex.Message))
{
}
catch (Exception ex) when (ex.Message == "海澜0")
{
Debug.LogWarning("异常0");
}
catch (Exception ex) when (ex.Message == "海澜1")
{
Debug.LogWarning("异常1");
}
}
public bool LogException(string ex)
{
Debug.LogWarning($"记录异常信息{ex}");
return false;
}
#endregion
#region nameof 表达式
public static string staticName = "静态菜鸟海澜";
public void TestNameOf(string firstName)
{
Debug.Log($"输出{firstName}");
Debug.Log($"输出{nameof(firstName)}");
Debug.Log($"输出{nameof(CSharpSix.staticName)}");
}
#endregion
#region Catch 和 Finally 块中的 Await
public async Task TestAwait()
{
try
{
Thread.Sleep(1000);
throw new Exception("菜鸟海澜");
}
catch (Exception ex) when (ex.Message.Contains("海澜"))
{
await LogExceptionAsync();
}
finally
{
await CloseConnectionAsync();
}
}
private Task CloseConnectionAsync()
{
Debug.Log("CloseConnectionAsync");
Thread.Sleep(1000);
return null;
}
private Task LogExceptionAsync()
{
Debug.Log("LogExceptionAsync");
Thread.Sleep(1000);
return null;
}
#endregion
#region 索引初始值设定项
private List<string> messages = new List<string>
{
"Page not Found",
"Page moved, but left a forwarding address.",
"The web server can't come out to play today."
};
public void aaa()
{
Dictionary<int, string> webErrors = new Dictionary<int, string>
{
[404] = "Page not Found",
[302] = "Page moved, but left a forwarding address.",
[500] = "The web server can't come out to play today."
};
}
//Dictionary<int, string> webErrors11 = new Dictionary<int, string>
//{
// [404] = "Page not Found",
// [302] = "Page moved, but left a forwarding address.",
// [500] = "The web server can't come out to play today."
//};
#endregion
#region 改进了重载解析
public static Task<int> DoThings()
{
return Task.FromResult(666);
}
#endregion