C#6.0新特性的学习笔记

官方文档为 :C#6.0新特性,需要学习的可以直接去看官方文档,下面是我对6.0的学习笔记。
C#6.0

只读属性

public string Test1 { get; }

当设置该属性仅读类型,只允许在类的构造函数中赋值。其他地方仅允许取值。

	class Program
    {
		public string Test1 { get; }
		public Program()
        {
            Test1 = "1";//不允许赋值
        }
	}

有些类似于readonly类型,如下

public static readonly string testReadOnly="b";

自动属性初始化表达式

语法糖,可以在属性后直接给对象赋值

public string Test2 { get; set; } = "b";

注意只有自动属性才可以赋值,也就是使用{ get; set; }
而不是

			get
            {
                return Test1;
            }
            set
            {
                if (value=="a")
                {
                    Test1 = value+"b";
                };
            }  //= "a"; 此时再赋值会提示只有自动实现的属性才具有初始值设定项

官方文档给出的例子是(list继承于ICollection)

public ICollection<double> Grades { get; } = new List<double>();

Expression-bodied 函数成员

之前版本的重写ToString方法为

		public override string ToString()
        {
            return base.ToString();
        }

现在使用表达式直接写成

public override string ToString() => $"{LastName}, {FirstName}";

这个$是C#6.0的新特性字符串内插,下面也会介绍到,这个表达式主体特性只能使用于方法和只读属性。个人觉得如果方法是复杂处理的话这种写法很容易乱,还不如直接写。属性还比较好一点。
表达式主体用法针对于方法的例子如下

using System;

public class Person
{
   public Person(string firstName, string lastName)
   {
      fname = firstName;
      lname = lastName;
   }

   private string fname;
   private string lname;

   public override string ToString() => $"{fname} {lname}".Trim();
   public void DisplayName() => Console.WriteLine(ToString());
}

class Example
{
   static void Main()
   {
      Person p = new Person("Mandy", "Dejesus");
      Console.WriteLine(p);
      p.DisplayName();
   }
}

表达式主体用法针对于属性的例子如下

public class Location
{
   private string locationName;

   public Location(string name)
   {
      locationName = name;
   }

   public string Name => locationName;
}

个人的理解为

public string Name => locationName;

类似于,给元素赋一个只读的属性

public string Name { get { return locationName; } }

using static

直接可以在类中直接使用方法,例如

String.Compare();

当声明using static System.String;
可以直接写成

Compare()

省的敲String了,但是需要注意引用时需要提供完全限定的类型名称(完整的命名空间名称以及类型名称),也就是using static System.String而不是using static String,但是你引用错了编译器也会抛异常提示。所以可以放心的using。

Null 条件运算符

这个记得在之前的C#版本中有一个语法糖,值类型不允许为空,这个特性我经常使用int? a = null;,这样值类型就允许为空了。
而NULL条件运算符为?.

var first = person?.FirstName;

官方文档解释很清楚 :如果 Person 对象是 null,则将变量 first 赋值为 null。 否则,将 FirstName 属性的值分配给该变量。 最重要的是,?. 意味着当 person 变量为 null 时,此行代码不会生成 NullReferenceException。 它会短路并返回 null。 还可以将 null 条件运算符用于数组或索引器访问。
person 的值是什么,以下表达式均返回 string。

first = person?.FirstName ?? "Unspecified";

上面这个代码很实用,之前很多行的代码一行就可以代替。就是判断?.左侧是否为空,为空就返回null。

字符串内插

非常喜欢的新特性,之前拼接string都是string.Format("{0},{1}", "s", "a")这种类似写法,现在可以无限的拼接字符串,并且没有限制。
官方说明 : 新的字符串内插功能可以在字符串中嵌入表达式。 使用 $ 作为字符串的开头,并使用 { 和 } 之间的表达式代替序号

public string FullName => $"{FirstName} {LastName}";

下面这种方式使用上面的Expression-bodied加字符串内插

public string GetGradePointPercentage() =>
    $"Name: {LastName}, {FirstName}. G.P.A: {Grades.Average():F2}";

异常筛选器

这个也是很喜欢的新特性,try catch 的时候不好去判断Exception的类型,却想针对异常去分别处理。之前我用的方法都是判断Exception ex,将ex.tostring()。后判断是否包含异常。
官方文档为*“异常筛选器”是确定何时应该应用给定的 catch 子句的子句 。 如果用于异常筛选器的表达式计算结果为 true,则 catch 子句将对异常执行正常处理。 如果表达式计算结果为 false,则将跳过 catch 子句。 一种用途是检查有关异常的信息,以确定 catch 子句是否可以处理该异常:*

			try
            {
                
            }
            catch(System.Net.Http.HttpRequestException e)
            {

            }
            catch (Exception ex) when (ex.Message.Contains(""))
            {

                throw;
            }

nameof 表达式

官方文档:nameof 表达式的计算结果为符号的名称。 每当需要变量、属性或成员字段的名称时,这是让工具正常运行的好办法。 nameof 的其中一个最常见的用途是提供引起异常的符号的名称:
需要变量名称时,旧版本可以考虑反射,现在直接用nameof(lastName),就可以直接获取到变量名称

Console.WriteLine(nameof(System.Collections.Generic));  // output: Generic
Console.WriteLine(nameof(List<int>));  // output: List
Console.WriteLine(nameof(List<int>.Count));  // output: Count
Console.WriteLine(nameof(List<int>.Add));  // output: Add

var numbers = new List<int> { 1, 2, 3 };
Console.WriteLine(nameof(numbers));  // output: numbers
Console.WriteLine(nameof(numbers.Count));  // output: Count
Console.WriteLine(nameof(numbers.Add));  // output: Add

Catch 和 Finally 块中的 Await

官方文档:在 catch 和 finally 子句中添加 await 支持的实现细节可确保该行为与同步代码的行为一致。 当在 catch 或 finally 子句中执行的代码引发异常时,执行将在下一个外层块中查找合适的 catch 子句。 如果存在当前异常,则该异常将丢失。 catch 和 finally 子句中的 awaited 表达式也会发生同样的情况:搜索合适的 catch,并且当前异常(如果有)将丢失。

主要是用在多线程异步中,之前版本,线程中异常会跑到外层块的catch,使用这个可以让日志记录等操作与代码编写的同步。这个个人觉得异步中使用不会太大。线程异常外部记录也是一样会记录异常信息以及代码异常的位置。

使用索引器初始化关联集合

官方文档说:可以将集合初始值设定项与 Dictionary<TKey,TValue> 集合和其他类型一起使用,看的我以为可以像python一样,不区分类型添加集合的数据,但实际不是,只是支持了可以使用符号 **[]**去包裹键,取值也支持用

private static Dictionary<int, string> web = 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."
        };

web[404]
有区别吗? 我觉得并没有?

改进了重载解析

这个只是对编译器的优化,理解下就好,官方说明如下

以前版本的 C# 编译器可能会发现涉及 lambda 表达式的一些方法不明确。 请考虑此方法:

static Task DoThings()
{
     return Task.FromResult(0);
}

在早期版本的 C# 中,使用方法组语法调用该方法将失败:

Task.Run(DoThings);

早期的编译器无法正确区分 Task.Run(Action)Task.Run(Func<Task>())。 在早期版本中,需要使用 lambda 表达式作为参数:

Task.Run(() => DoThings());

C# 6 编译器正确地确定 Task.Run(Func<Task>()) 是更好的选择。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值