C# 二十年语法变迁之 C# 2,C# 3 ,C# 4参考
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参考的更多相关文章
- SQL 2008 RAISERROR语法在SQL 2012/2014不兼容问题
原文 旧的RAISERROR语法在SQL 2012不兼容问题 raiserror 写法: SQL 2008: raiserror 55030 'text error' SQL 2012: raiser ...
- 基本 XAML 语法指南
我们介绍了 XAML 语法规则,以及用于描述 XAML 语法中存在的限制或选项的术语.当出现以下情况时你会发现本主题很有用:不熟悉 XAML 语言的使用,希望加强对术语或某些语法部分的理解,或者对 X ...
- 深入Dockerfile(一): 语法指南(转)
最近在学习K8S,发现这两篇文章还不错,转了过来 docker官方文档Dockerfile reference的笔记. 一.机制 1.1 构建 docker构建一个镜像,需要: Dockerfile文 ...
- ANTLR4权威指南 - 第6章 尝试一些实际中的语法
第6章 尝试一些实际中的语法 在前一章,我们学习了通用词法结构和语法结构,并学习了如何用ANTLR的语法来表述这些结构.现在,是时候把我们学到的这些用来构建一些现实世界中的语法了.我们的主要目标是,怎 ...
- Markdown分级语法手册
目录 前言(可以不看) 基本语法(18) 1. 标题:# 2. 无序列表:- 3. 有序列表:1. 4. 斜体:* 5. 粗体:** 6. 加粗斜体:*** 7. 删除线:~~ 8. 分隔线:--- ...
- 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 ...
- ABAP 新语法记录(一)
原文链接:https://www.cnblogs.com/learnning/p/10647174.html 主要内容 内联声明 构造表达式 内表操作 Open SQL 其他 本文列出了ABAP新语法 ...
- ABAP 新语法-实例讲解
主要内容 内联声明 构造表达式 内表操作 Open SQL 其他 本文列出了ABAP新语法的一些使用方式,供大家学习参考. 内联声明 代码实现: *&--------------------- ...
- 前端知识(二)05-Eslint语法规范检查-谷粒学院
目录 一.ESLint简介 二.启用ESLint 1.ESLint插件安装 2.插件的扩展设置 3.确认开启语法检查 三.ESLint规则说明 1.规则说明 2.语法规则 一.ESLint简介 ESL ...
- Django笔记&教程 3-3 模板常用语法
Django 自学笔记兼学习教程第3章第3节--模板常用语法 点击查看教程总目录 本文主要参考:https://docs.djangoproject.com/en/2.2/ref/templates/ ...
随机推荐
- Hystrix 实现服务熔断与降级
本文为博主原创,未经允许不得转载: 目录: 1. 服务雪崩,服务熔断,服务降级概念 2. Hystrix 概念 3. Hystrix 使用及默认配置 4. @HystrixCommond 注解使用 5 ...
- Java-Enum常量特定方法
OnJava8-Enum-常量特定方法 用枚举实现责任链模式 责任链(Chain Of Responsibility)设计模式先创建了一批用于解决目标问题的不同方法,然后将它们连成一条"链& ...
- [转帖]linux下查看内存频率,内核函数,cpu频率
https://www.cnblogs.com/lovesKey/p/10900501.html 查看CPU: cat /proc/cpuinfo # 总核数 = 物理CPU个数 X 每颗物理CPU的 ...
- [转帖]062、监控指标之PD
PD相关 Grafana 监控 PD -> PD Dashboard 是否存在异常状态的TiKV Grafana 监控 PD -> Region health 大表清理后,出现了大量的空r ...
- [转帖]公钥基础设施(PKI,Public Key Infrastructure)闲谈
https://zhuanlan.zhihu.com/p/384436119 背景 在现实空间中,人类的活动范围和接触人的范围有限,人和人最初的信任是建立在小团体或部落内部.随着全球化进展,人类的活动 ...
- 工单 工序外协 更改PR/PO
工序外协详解介绍'https://blog.csdn.net/weixin_43814706/article/details/113586961' 需求:创建工序委外的工单时更改对应PR/PO 行文本 ...
- 记一次JSF异步调用引起的接口可用率降低
前言 本文记录了由于JSF异步调用超时引起的接口可用率降低问题的排查过程,主要介绍了排查思路和JSF异步调用的流程,希望可以帮助大家了解JSF的异步调用原理以及提供一些问题排查思路.本文分析的JSF源 ...
- 京东哥伦布即时设计平台ChatGPT落地实践
一.平台介绍 即时设计平台是一个即时搭建c端楼层的开发平台,支持通过导入relay设计稿url完成Ui2Code,在此基础上完成前端可视化搭建,同时支持通过ChatGPT完成一句话需求,搭建后的楼层自 ...
- Vue中this.$options.data()和this.$data知多少?
1.场所描述 如何获取vue-data中的所有值? 如何获取vue-data中的某一个值? 如何获取vue-data中的初始值? 如何设置data中的值位初始值? 2.主角登场 this.$optio ...
- 关于async函数的错误处理
1. 关于async函数的错误处理 有些时候,我们请求的接口可能会报错: 从而导致后面的代码无法去执行: 这样就会造成页面上某些状态出错! 那么怎么样才能 既能捕获到错误 还能让代码往后面执行呢 2. ...