XIKEW.COM - 实用教程 - C# 特性整理 2.0 ~ 10.0 - 实用教程,c#, csharp - 作为一个半路出家的人来说,对C#语言的学习对于每一个版本的新特性了解是非常必要的

C# 特性整理 2.0 ~ 10.0
C# 12/2/2021 10:21:02 AM 阅读:132

网页捕获_812022_121237_image.baidu.com.jpeg

作为一个半路出家的人来说,对C#语言的学习对于每一个版本的新特性了解是非常必要的 关键字: c#, csharp [[toc]]

C#的设计目标

  • 旨在是一种简单,现代,通用的面向对象编程语言。
  • 语言及其实现应该为软件工程原理提供支持,例如强类型检查,数组维度检查,未初始化的变量引用检测以及自动垃圾收集。软件的鲁棒性,耐久性和程序员的生产力很重要。
  • 旨在用于开发适用于分布式环境中部署的软件组件。
  • 便携性对于源代码和程序员非常重要,特别是已经熟悉C和C ++的程序员。
  • 支持国际化是非常重要的。
  • C#适用于为托管和嵌入式系统编写应用程序,从使用复杂的操作系统到非常小的专用功能都非常适用。
  • 虽然C#应用程序在内存和处理能力要求方面是经济的,但是该语言并不打算直接用C或汇编语言直接与性能和尺寸进行竞争。

C# 2.0 (记录重点)

泛型

匿名方法

labmba的前身

迭代器

可空类型 (nullable type)

Getter / setter单独可访问性

方法组转换(代表)

Co- and Contra-variance for delegates

静态类

Delegate inference

C# 3.0

LINQ查询表达式

令C#可以直接编写查询并以静态方法检查其正确性

隐式类型局部变量

var 关键字允许在声明中省略变量类型,然后由编译器推断其类型

对象和收集初始化器

在初始化器里直接设置对象的可访问字段或属性

自动实现的属性

匿名类型

扩展方法

Lambda表达式

表达树

一种特殊类型Expression的Lambda表达式的DOM(文档对象类型) 表达式树使LINQ查询能够远程执行,因为它们可以在运行时进转换和翻译.

C# 4.0

动态绑定

dynamic 类型是一种静态类型,类型为 dynamic 的对象会跳过静态类型检查。 大多数情况下,该对象就像具有类型 object 一样。

dynamic dyn = 1;
object obj = 1;

// dyn = dyn + 3; 不会报错
// obj = obj + 3; 会报错 

System.Console.WriteLine(dyn.GetType());
System.Console.WriteLine(obj.GetType());

//输出同时为System.Int32

可选参数

可选参数就是带有默认值的函数参数

void Foo(int x = 20) { ... }

命名参数

除了按照顺序位置来确定参数外,还可以用名称来确定参数

void Foo(int x = 0, int y) => x + y;

对于该函数的调用有如下方法

Foo(1, 2);

Foo(x: 1, y: 2);

Foo(1, y:2);

Foo(y: 2);

协变和逆变扩展

加入了对Generic Type的Co&Contravariance的支持。 具体可以参见文章 https://blog.csdn.net/weixin_30672019/article/details/96082697

嵌入式互操作类型(“NoPIA”)

暂不记录...

C# 5.0

异步方法 async 和 await

await 是为了让异步操作更像同步

function 摇色子(){
    return new Promise((resolve, reject)=>{
        let sino = parseInt(Math.random() * 6 +1)
        setTimeout(()=>{
            resolve(sino)
        },3000)
    })
}
async function test(){
    let n = await 摇色子()
    console.log(n)
}
test()

CallerInfoAttributes

using System;
using System.Runtime.CompilerServices;

namespace TestPro
{
    class Program
    {
        public static void Main()
        {
            Log("Test.");
        } 

        // 对日志消息进行记录,同时所有内容均有默认值,如果获取失败,则使用默认值。
        public static void Log(string message,
            [CallerMemberName] string callerName = "unknown", 
            [CallerFilePath] string callerFilePath = "unknown", 
            [CallerLineNumber] int callerLineNumber = -1)
        {
            Console.WriteLine("Message: {0}", message);
            Console.WriteLine("Caller's Name: {0}", callerName);
            Console.WriteLine("Caller's FilePath: {0}", callerFilePath);
            Console.WriteLine("Caller's LineNumber: {0}", callerLineNumber);
        }
    }
}

输出一下内容

Message: Test.
Caller Name: Main
Caller FilePath: C:UsersAdministratorsource
eposTestProProgram.cs
Caller Line number: 10

C# 6.0

Roslyn编译器

新的编译器将一整条编译流水通过程序库进行开放,使得对各种源代码进行分析 可以参见 https://github.com/dotnet/roslyn

字符串插值

更加简单的方式代替 string.Format

string s = $"it is ${DateTime.Now.DayOfWeek} today";

将静态类型成员导入命名空间

using static

using static System.Console;
...
WriteLine("Hello world");

异常过滤器

可以在 catch 后追加条件

try {
    ...
} catch (Exception ex when (ex.Status == WebExceptionStatus.Timeout)) {
  ...  
}

指的一提的是在Catch和Finally中使用Await

属性初始化器

初始化的时候自动设置默认值

public DateTime TimeCreated {get;set;} = DateTime.Now;

只读属性初始化器

这种初始化同样支持只读属性

public DateTime TimeCreated {get;} = DateTime.Now;

索引器初始化器

还可以对索引器进行初始化

var dict = new Dictionary<int, string>()
{
    [3] = "three",
    [10] = "ten"
};

null的简化判断

前该赋值操作会报错NullReferenceExc

System.Text.StringBuilder sb = null;
string result = sb?.ToString(); // result 为 null

nameof operator

nameof 可以返回 变量、类型、其他符号 的名称

int capacity = 123;
string x = nameof(capacity); // x is "capacity"
string y = nameof(Uri.Host); // y is "Host"

表达式函数体(胖箭头语法)

public int TimesTwo(int x) => x * 2;
public string SomeProperty => "Property value";

C# 7.0

可以参考连接 https://devblogs.microsoft.com/dotnet/whats-new-in-csharp-7-0/

out变量

out 使用更容易

bool successful = int.TryParse("123", out int result);
Console.WriteLine(result);

如果调用有多个out参数的方法时, 可以使用下划线来忽略参数

testfunc(out _, out _, out int result, out _);
Console.WriteLine(result);

模式

is 运算符 也成为模式变量

if(x is string) { ... }

简化了类型转换

object o = 1;

//老方法
int i = Convert.ToInt32(o);
Console.WriteLine(i + 1);

//运用 is 模式匹配
if (o is int i) {
    Console.WriteLine(i + 1);
}

switch 同样支持模式, 配合 when 判断条件; 同时支持 null 条件

switch(x){
    case int i:
    break;
    case string s:
    break;
    case bool b when b == true:
    break;
    case null:
    break;
}

元组

元祖实际上是使用了System.ValueTuple<...>泛型结构的语法糖

var bob = ("Bob", 23)
Console.WriteLine(bob.Item1);
Console.WriteLine(bob.Item2);

我们还可以对元祖的元素进行命名

var tuple = (Name:"Bob", Age:23);
Console.WriteLine(tuple.Name);
Console.WriteLine(tuple.Age);

元祖也可以代替out的参数返回功能

static (int row, int column) GetFilePosition() => (3, 10);
    
static void Main() {
    var pos = GetFilePosition();
    Console.WriteLine(pos.row);
    Console.WriteLine(pos.column);
}

元祖隐式地支持解构模式,因此很容易解构为若干个独立变量

static void Main() {
    (int row, int column) = GetFilePosition();
    Console.WriteLine(row);
    Console.WriteLine(column);
}

解构器

解构器跟构造器的作用正好相反,它将字段反向赋值给变量

public class Person {
    public void Deconstruct (out string firstName, out string lastName) 
    {
        int spacePos = name.IndexOf(' ');
        firstName = name.Substring(0, spacePos);
        lastName = name.Substring(spacePos + 1);
    }
}

以特定的语法进行调用

var joe = new Person("Joe Bloggs");
var (first, last) = joe;
Console.WriteLine(first);
Console.WriteLine(last);

局部函数

局部方法同样支持 lambda

void WriteCubes() {
    Console.WriteLine(Cube(1));
    Console.WriteLine(Cube(2));
    Console.WriteLine(Cube(3));
    
    int Cube(int value) => value * vaule * vaule;
}

数字分隔符

使用下划线来改善可读性,会被编译器忽略

int million = 1_000_000;
//二进制加0b前缀
var b = 0b1010_1010_1010_1100;

局部引用和引用返回

public ref int Find(int number, int[] numbers)
{
    for (int i = 0; i < numbers.Length; i++)
    {
        if (numbers[i] == number) 
        {
            return ref numbers[i]; // return the storage location, not the value
        }
    }
    throw new IndexOutOfRangeException($"{nameof(number)} not found");
}

int[] array = { 1, 15, -39, 0, 7, 14, -12 };
ref int place = ref Find(7, array); // aliases 7's place in the array
place = 9; // replaces 7 with 9 in the array
WriteLine(array[4]); // prints 9

扩展异步返回类型

改进后不需要强制异步操作时必须返回 void, Task or Task 例如,我们计划使用 ValueTask < t > struct 类型。构建它是为了防止在等待时异步操作的结果已经可用的情况下分配 Task < t > 对象。例如,对于涉及缓冲的许多异步场景,这可以大大减少分配数量,并导致显著的性能提升。

表达式的构造函数和finalizers

public class Person {
    string name;
    public Person (string name) => Name = name;
    
    ~Person () => Console.WriteLine("finalize");
}

throw表达式

throw 可以出现在函数体中

public string Foo() => throw new Notlmple-mentedException();

throw 可以出现在三元运算符中

string Capitalize(string value) => value == null ? throw new ArgumentException("value") : value == "?" : char.ToUpper(value[0]) + value.Substring(1);

C# 8.0 - C# 10.0

官方有非常详细的手册,推荐查阅 快速查阅