记录一些对写代码会有帮助,但是平时像不太到的新特性
c#6.0
自动属性初始化
在类初始化时,会使用后面的表达式初始化该属性
public ICollection<double> Grades { get; } = new List<double>();
表达式作为成员主体
这个和上一个可能有点像,但是作用完全不同,这个属性/函数的值,会在每次调用时重新计算,而不是初始化时
public override string ToString() => $"{LastName}, {FirstName}";
//或者
public string FullName => $"{FirstName} {LastName}";
static引用
通过在using
后增加static,可以直接引用命名空间中的静态方法,而不用在前面带上类名
using static System.Math;
此后,可以直接引用Sin
/Sqrt
等方法,而不用写上Math.Sin
空条件操作符?.
原来如下操作
var handler = this.SomethingHappened;
if (handler != null)
handler(this, eventArgs);
可以被简化为:
// preferred in C# 6:
this.SomethingHappened?.Invoke(this, eventArgs);
字符串拼接
这个是非常方便的特性,从传统的基于位置的字符串格式化
public string FullName
{
get
{
return string.Format("{0} {1}", FirstName, LastName);
}
}
通过在字符串前增加$
符号,可以直接在字符串中带入变量:
public string FullName => $"{FirstName} {LastName}";
异常过滤
try/catch
语句除了根据异常类型,还能通过when
操作符过滤额外条件:
public static async Task<string> MakeRequest()
{
WebRequestHandler webRequestHandler = new WebRequestHandler();
webRequestHandler.AllowAutoRedirect = false;
using (HttpClient client = new HttpClient(webRequestHandler))
{
var stringTask = client.GetStringAsync("https://docs.microsoft.com/en-us/dotnet/about/");
try
{
var responseText = await stringTask;
return responseText;
}
catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301"))
{
return "Site Moved";
}
}
}
nameof
表达式
nameof返回变量名称的字符串表达
if (IsNullOrWhiteSpace(lastName))
throw new ArgumentException(message: "Cannot be blank", paramName: nameof(lastName));
当然可以直接在字符串中写入固定的值,不过通过nameof,当通过vs重构变量名时,这里的代码编辑器会帮助自动修改,这是nameof的好处
await
允许被用在catch/finally
代码块中
这在之前的c#是不允许的。不过要小心,不要引入新的异常,要不原有异常就看不到了。。。
通过索引初始化
之前数组型的集合可以被容易的初始化,而字典等非线性则不如数组初始化那么轻松,不过现在c#也支持了更为友好的初始化语法:
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."
};
为数组初始化扩展Add
方法
Collection
如果想使用集合初始化方式初始化一个类,那么类必须实现Add
方法
public class Enrollment : IEnumerable<Student>
{
private List<Student> allStudents = new List<Student>();
public void Enroll(Student s)
{
allStudents.Add(s);
}
public IEnumerator<Student> GetEnumerator()
{
return ((IEnumerable<Student>)allStudents).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<Student>)allStudents).GetEnumerator();
}
}
//这在之前版本是不行的,因为Enrollment类只有Enroll,没有Add方法
var classList = new Enrollment()
{
new Student("Lessie", "Crosby"),
new Student("Vicki", "Petty"),
new Student("Ofelia", "Hobbs")
};
而现在,通过将Enroll
对应到Add
方法,就可以了。
public static class StudentExtensions
{
public static void Add(this Enrollment e, Student s) => e.Enroll(s);
}
更好的重载判断
static Task DoThings()
{
return Task.FromResult(0);
}
Task.Run(DoThings);
在之前版本,编译器无法识别调用的是Task.Run(Action)
还是Task.Run(Func<Task>())
,会报错
新版的编译器能够正确将其识别为Task.Run(Func<Task>())
了。
确定编译输出
c#编译出来的二进制文件,即使源代码没有改,也会因为添加时间戳、GUID等每次独立生成的信息而有所不同
通过增加-deterministic
选项,能让编译器每次生成完全一致的二进制输出