C# 二十年语法变迁之 C# 2,C# 3 ,C# 4参考

https://benbowen.blog/post/two_decades_of_csharp_i/

自从 C# 于 2000 年推出以来,该语言的规模已经大大增加,我不确定任何人是否有可能在任何时候都对每一种语言特性都有深入的了解。因此,我想写一系列快速参考文章,总结自 C# 2.0 以来所有主要的新语言特性。我不会详细介绍它们中的任何一个,但我希望这个系列可以作为我自己(希望你也是!)的参考,我可以不时回过头来记住我使用的工具工具箱里有。

开始之前的一个小提示:我将跳过一些更基本的东西(例如 C# 2.0 引入了泛型,但它们的使用范围如此广泛,以至于它们不值得包括在内);而且我还可以将一些功能“粘合”在一起,以使其更简洁。本系列并不打算成为该语言的权威或历史记录。相反,它更像是可能派上用场的重要语言功能的“备忘单”。

C# 2.0

可空值类型

这些允许您将null指定为任何结构变量的潜在值(否则null将无效):

class MyClass {
public int MyInt { get; }
public int? MyNullableInt { get; } // This property can be null even though it's of type 'int' public MyClass(int? input) { // input can be null
MyInt = input != null ? input.Value : 0; // .Value throws an exception when accessed if input is null
MyNullableInt = input;
}
} // .. static void Test() {
var mc = new MyClass(null);
if (mc.MyNullableInt == null) Console.WriteLine("Was null!");
}

• “可空值类型”

从技术上讲,任何可空值对象的类型都是Nullable,其中T是实际包含的类型(即int?与Nullable相同)。Nullable本身就是一个结构,因此理论上检查该类型的实例是否为null是没有意义的,但是编译器和Nullable上重写的Equals()实现的组合允许我们将实例视为类型好像它确实有意义。您还可以通过使用其HasValue属性来确定Nullable实例是否为“非空” 。

部分类型partial class

此功能允许将大型类型(类、接口或结构)的实现分散到多个文件中。

// File: ExampleClass.Alpha.cs

public partial class ExampleClass {
public void DoAlphaOne() { ... } public void DoAlphaTwo() { ... }
} // File: ExampleClass.Beta.cs public partial class ExampleClass {
public void DoBetaOne() { ... } public void DoBetaTwo() { ... }
} // Elsewhere static void Test() {
var ec = new ExampleClass(); ec.DoAlphaOne();
ec.DoBetaTwo();
// etc
}

• “部分类”

空值合并

此功能允许创建计算为链中第一个非空值的表达式:

var neverNullString = _stringField ?? stringParameter ?? "Default";

全屏查看代码• “Null Coalesceing”

此代码会将neverNullString设置为_stringField,除非_stringField为空;在这种情况下,它将把它设置为stringParameter,除非stringParameter也为空,在这种情况下,它将把它设置为文字值"Default"。

迭代器生成器(Yield)

此功能允许您通过在可枚举中“生成”元素来创建IEnumerable或IEnumerator。下面的例子演示了我们如何创建一个由三个或六个整数组成的序列:

public IEnumerable<int> GetOneTwoThree(bool includeNegative = false) {
yield return 1;
yield return 2;
yield return 3;
if (!includeNegative) yield break;
yield return -1;
yield return -2;
yield return -3;
} // .. Console.WriteLine(String.Join(",", GetOneTwoThree())); // Prints "1,2,3" on console
Console.WriteLine(String.Join(",", GetOneTwoThree(true))); // Prints "1,2,3,-1,-2,-3" on console

全屏查看代码• “收益回报和中断”

C# 3.0

扩展方法

此功能允许在预先存在的类型上定义新方法。这对于向您无法控制的类型添加功能很有用。以下示例显示

如何将ToString()的重载添加到double类型:

public static class DoubleExtensions {
public static string ToString(this double @this, int numDecimalPlaces) {
return @this.ToString("N" + numDecimalPlaces.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture);
}
} // ... Elsewhere ... // Will write something like "3.5"; assuming YearsWorkedAtCompany is a double:
Console.WriteLine(user.YearsWorkedAtCompany.ToString(1));

• “ ToString 扩展”

集合初始化器

此功能允许实例化各种集合类型,同时向它们添加初始值:

var myArray = new[] { 1, 2, 3, 4, 5 }; // myArray is an int[] of length 5
var myList = new List<int> { 1, 2, 3, 4, 5 }; // myList is a List<int> with 5 elements
var myDict = new Dictionary<int, int> { { 1, 100 }, { 2, 200 } }; // myDict is a Dictionary with 2 key-value pairs

• “集合初始化器”

对象初始化器

此功能允许在其实例化点设置对象的内联属性:

class Person {
public string Name { get; set; }
public int Age { get; set; }
} static void Test() {
var person = new Person {
Name = "Ben",
Age = 30
};
}

• “对象初始化器”

Partial Methods

与部分类一样,这允许您在不同的文件中编写方法的两个或多个部分。不保证执行顺序。该方法必须具有void返回类型,并且必须是私有的。

// File: ExampleClass.Alpha.cs

public partial class ExampleClass {
public void Print() => DoThing(); partial void DoThing() {
Console.WriteLine("AAA");
}
} // File: ExampleClass.Beta.cs public partial class ExampleClass {
partial void DoThing() {
Console.WriteLine("BBB");
}
} // Elsewhere static void Test() {
var ec = new ExampleClass(); ec.Print(); // Prints AAA and BBB to console (order unspecified).
}

• “部分方法”

自动生成的代码可以使用空的部分方法声明,以允许用户在需要时手动插入自定义逻辑:

// File: ExampleClass.AutoGenerated.cs

public partial class ExampleClass {
public void SomeAutoGeneratedMethod() {
DoSomethingOnAutoGenMethodCall(); // do other stuff
} partial void DoSomethingOnAutoGenMethodCall(); // If user does not supply implementation in ExampleClass.User.cs this method will not even be compiled and calls to it will be removed
} // File: ExampleClass.User.cs public partial class ExampleClass {
partial void DoSomethingOnAutoGenMethodCall() {
Console.WriteLine("SomeAutoGeneratedMethod Invoked");
}
}

• “自动生成代码的部分方法”

C# 4.0

动态/后期绑定类型

引入了动态类型以允许“后期绑定”类型解析。我偶尔使用动态的一件事是作为一种更简洁的反射形式:

class GenericClass<T1, T2> {
public T1 SomeComplexMethod<T3>(T2 inputA, T3 inputB) {
// ...
}
} class Program {
static void Main() {
var gc = new GenericClass<int, string>();
var resultA = InvokeComplexMethodReflectively(gc, "Hi", 3f);
var resultB = InvokeComplexMethodDynamically(gc, "Hi", 3f); Console.WriteLine(resultA);
Console.WriteLine(resultB);
} static object InvokeComplexMethodReflectively(object genericClassInstance, string inputA, float inputB) {
var openMethodDefinition = genericClassInstance.GetType().GetMethod("SomeComplexMethod");
var genericMethodDefinition = openMethodDefinition.MakeGenericMethod(typeof(float));
return genericMethodDefinition.Invoke(genericClassInstance, new object[] { inputA, inputB });
} static object InvokeComplexMethodDynamically(object genericClassInstance, string inputA, float inputB) {
return ((dynamic) genericClassInstance).SomeComplexMethod(inputA, inputB);
}
}

• “动态替代反射”

很多人根本就对使用动态有所保留,但是后期绑定无论如何都是在内部使用反射解决的,所以它真的可以被认为是反射的语法糖。此外,由于绑定信息的缓存,动态实际上通常可以胜过使用“纯”反射的相同方法。

C# 还添加了一个名为ExpandoObject的新类型,它类似于字典,但键是动态添加的成员:

static void Test() {
dynamic user = new ExpandoObject();
user.Name = "Ben";
user.Age = 30; // Prints "User Name is Ben" and "User Age is 30"
foreach (var kvp in (IDictionary<String, Object>) user) {
Console.WriteLine($"User {kvp.Key} is {kvp.Value}");
}
}

• “ExpandoObject”

可选参数

可选参数是具有指定默认值的方法的参数,因此不需要由调用者指定:

// 'nickname' is optional here
public static void MethodWithOptionalArgs(string name, int age, string nickname = null) {
// ...
} static void Test() {
MethodWithOptionalArgs("Ben", 30); // No nickname specified, 'null' will be passed in
}

• “可选参数”

可选参数必须始终排在参数列表的最后。

命名参数

C# 4.0 中的命名参数允许在有多个参数时指定特定的可选参数:

public static void MethodWithOptionalArgs(string name, int age, string nickname = null, bool married = false, string address = null) {
// ...
} static void Test() {
MethodWithOptionalArgs("Ben", 30, address: "Noveria"); // 'nickname' and 'married' are left unspecified
}

• “可选参数”

从 C# 7.2 开始,即使参数不是可选的,也可以命名。我偶尔在指定一个布尔参数时使用它,否则它很难理解:

static void Test() {
CreateTables(true); // What is true? CreateTables(deletePreviousData: true); // Ahh... Much better.
}

• “可选参数”

泛型类型参数的协方差和逆变

在使用泛型类型参数创建接口或委托类型时,我们可以指定这些类型参数是协变的或逆变的:

interface ICovariant<out T> { }
interface IContravariant<in T> { } static void Test() {
ICovariant<object> covariantObj;
ICovariant<int> covariantInt = GetCovariant<int>(); covariantObj = covariantInt; // "out T" in ICovariant allows this IContravariant<object> contravariantObj = GetContravariant<object>();
IContravariant<int> contravariantInt; contravariantInt = contravariantObj; // "in T" in IContravariant allows this
}

• “接口中的协变和逆变通用参数”

delegate T Covariant<out T>();
delegate void Contravariant<in T>(T value); static void Test() {
Covariant<object> covariantObj;
Covariant<int> covariantInt = () => 3; covariantObj = covariantInt; Contravariant<object> contravariantObj = myObj => Console.WriteLine(myObj);
Contravariant<int> contravariantInt; contravariantInt = contravariantObj;
}

• “委托中的协变和逆变通用参数”

当指定通常作为接口输出 的对象类型时,协方差很有用;因为我们通常不介意实际的输出类型是否是指定类型的子类型。在指定通常作为接口输入

的对象类型时,逆变很有用。因为我们通常不介意预期的输入类型是否是给定类型的父类型。 与其记住“contra”和“co”方差之间的区别,我发现记住in用于输入而out用于输出(通常,无论如何)是有用的。

C# 二十年语法变迁之 C# 2,C# 3 ,C# 4参考的更多相关文章

  1. SQL 2008 RAISERROR语法在SQL 2012/2014不兼容问题

    原文 旧的RAISERROR语法在SQL 2012不兼容问题 raiserror 写法: SQL 2008: raiserror 55030 'text error' SQL 2012: raiser ...

  2. 基本 XAML 语法指南

    我们介绍了 XAML 语法规则,以及用于描述 XAML 语法中存在的限制或选项的术语.当出现以下情况时你会发现本主题很有用:不熟悉 XAML 语言的使用,希望加强对术语或某些语法部分的理解,或者对 X ...

  3. 深入Dockerfile(一): 语法指南(转)

    最近在学习K8S,发现这两篇文章还不错,转了过来 docker官方文档Dockerfile reference的笔记. 一.机制 1.1 构建 docker构建一个镜像,需要: Dockerfile文 ...

  4. ANTLR4权威指南 - 第6章 尝试一些实际中的语法

    第6章 尝试一些实际中的语法 在前一章,我们学习了通用词法结构和语法结构,并学习了如何用ANTLR的语法来表述这些结构.现在,是时候把我们学到的这些用来构建一些现实世界中的语法了.我们的主要目标是,怎 ...

  5. Markdown分级语法手册

    目录 前言(可以不看) 基本语法(18) 1. 标题:# 2. 无序列表:- 3. 有序列表:1. 4. 斜体:* 5. 粗体:** 6. 加粗斜体:*** 7. 删除线:~~ 8. 分隔线:--- ...

  6. Atitit.sql ast 表达式 语法树 语法 解析原理与实现 java php c#.net js python

    Atitit.sql ast 表达式 语法树 语法 解析原理与实现 java php c#.net js python 1.1. Sql语法树 ast 如下图锁死1 2. SQL语句解析的思路和过程3 ...

  7. ABAP 新语法记录(一)

    原文链接:https://www.cnblogs.com/learnning/p/10647174.html 主要内容 内联声明 构造表达式 内表操作 Open SQL 其他 本文列出了ABAP新语法 ...

  8. ABAP 新语法-实例讲解

    主要内容 内联声明 构造表达式 内表操作 Open SQL 其他 本文列出了ABAP新语法的一些使用方式,供大家学习参考. 内联声明 代码实现: *&--------------------- ...

  9. 前端知识(二)05-Eslint语法规范检查-谷粒学院

    目录 一.ESLint简介 二.启用ESLint 1.ESLint插件安装 2.插件的扩展设置 3.确认开启语法检查 三.ESLint规则说明 1.规则说明 2.语法规则 一.ESLint简介 ESL ...

  10. Django笔记&教程 3-3 模板常用语法

    Django 自学笔记兼学习教程第3章第3节--模板常用语法 点击查看教程总目录 本文主要参考:https://docs.djangoproject.com/en/2.2/ref/templates/ ...

随机推荐

  1. C#实现斐波拉切数列求和

    C#实现斐波拉切数列求和 private void button1_Click(object sender, EventArgs e) { listBox1.Items.Clear();//清空Lis ...

  2. 一文看完String的前世今生,内容有点多,请耐心看完!

    写在开头 String字符串作为一种引用类型,在Java中的地位举足轻重,也是代码中出现频率最高的一种数据结构,因此,我们需要像分析Object一样,将String作为一个topic,单独拿出来总结, ...

  3. MAUI使用Masa blazor组件库

    上一篇(点击阅读)我们实现了UI在Web端(Blazor Server/Wasm)和客户端(Windows/macOS/Android/iOS)共享,这篇我加上 Masa Blazor组件库的引用,并 ...

  4. SV 接口中的clocking

    接口 module可以例化模块,可以例化接口 接口不能例化模块 采样和数据驱动 时钟驱动数据,数据会有延迟,RTL仿真的时候,不会仿真出这个延时;RTL仿真的时候,不会仿真出寄存器的延时;只有在门级仿 ...

  5. [转帖]堆表(HOT)和索引组织表(IOT)优缺点

      转载于: https://www.ywnds.com/?p=7702 一.堆表和索引组织表 NOTE 堆表也可以称之为 HOT,索引组织表也可以称之为 IOT,下面没有特别说明,两者都是一个意思. ...

  6. [转帖]MySQL 8.2.0 GA

    https://cloud.tencent.com/developer/article/2353798 MySQL新的进化版8.2.0于2023年10月25日发行,让我们一起快速浏览一下该版本发生哪些 ...

  7. [转帖]CentOS8时间同步服务

    时间同步服务 CentOS7之前的版本用的是ntpdate服务,之后用的是chrony服务 默认是安装的了 查看版本 [root@centos8 ~]#rpm -qi chrony Name : ch ...

  8. 不同linux发行版 FIO测试结果总结

    不同linux发行版 FIO测试结果总结 背景 机器来源 配置: 2路28核心Golden 6330 2.0Ghz 512G内存 硬盘 24块 960G SSD (22块 Raid5 + 2块 hot ...

  9. Docker 镜像减少体积的思路和方法

    Docker 镜像减少体积的思路和方法 背景 有一个项目感觉镜像有点大 这边同事喊着一起帮忙处理一下. 今天基本上就在客户现场进行处理了. 想着应该把自己想到的东西整理一下. 整体思路 1. 清理do ...

  10. buildkit ctr 与 k3s的简单学习

    摘要 前面一部分学习了 buildkit的简单搭建 也学习会了如果build images的简单处理 但是搭建镜像只是万里长征第一步. 如何进行微服务部署,才是关键的第二步. 公司最近使用基于K3S的 ...