C# 语法糖详解

定义

语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。

它可以使程序员更加容易去使用这门语言:操作可以变得更加清晰、方便,或者更加符合程序员的编程习惯。简而言之,语法糖就是一种便捷写法。

1. 自动属性

未简化:手写私有变量+公有属性

csharp 复制代码
private string _name;
public string Name
{
	get { return _name; }
	set { _name = value; }
}
//声明空属性,编译器自动生成对应私有成员字段。
public string Name { get; set; }

2. 参数默认值和命名参数

使用的指导原则:

1、可以为方法和有参属性指定默认值

2、有默认值的参数,必须定义在没有默认值的参数之后

3、默认参数必须是常量

4、ref和out参数不能指定默认值

csharp 复制代码
public class User
{
	public string Name { get; set; }
	public int Age { get; set; }

	// 自动属性默认初始化
	public string Address { get; set; } = "江苏";

	// 设置参数默认值(age)
	public User(string name, string address, int age = 18)
	{
		this.Name = name;
		this.Age = age;
		this.Address = address;
    }
}
// 命名参数(指定address参数)
User user = new User("小王",address:"苏州");

3.类型实例化

csharp 复制代码
// 使用对象初始化器:{},使用对象初始化器,必须提供一个无参的构造函数,可以只给部分属性初始化
User user = new User()
{
 	Name = "小王",
	Age = 18,
	Address = "苏州",
 };

4.集合

4.1初始化List集合的值

csharp 复制代码
// 简化之前
List<string> listString = new List<string>();
listString.Add("小王");
listString.Add("小贤");

// 简化后
List<string> listString = new List<string>() {
	"小王",
	"小贤",
};

4.2取List的值

csharp 复制代码
// 简化之前
foreach (string str in listString)
{
	Console.WriteLine(str);
}
// 简化之后
listString.ForEach(s => Console.WriteLine(s));

5. 隐式类型(var)

程序员在声明变量时可以不指定类型,由编译器根据值来指定类型

var定义变量有以下四个特点:

1、必须在定义时初始化

2、一旦初始化完成,就不能再给变量赋与初始值不同类型的值了

3、var要求是局部变量

4、使用var定义变量和object不同,它在效率上和使用强类型方式定义变量完全一样

csharp 复制代码
// 1.隐式类型在定义时必须初始化
//var name; 报错
var name = "小王";
// 2.可以用同类型的其他隐式类型变量来初始化新的隐式类型变量
var age = 18;
var ageTwo = age;
// 3.也可以用同类型的字面量来初始化隐式类型变量
var name = "小王";
name = "小贤";
// 4.隐式类型局部变量还可以初始化数组而不指定类型
var array = new List<string>() { "小王","小贤",};

6.扩展方法

扩展方法使你能够向现有类型"添加"方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用。

注意:定义扩展方法的类必须和使用地方的类命名空间相同(如果不同命名空间记得先引入命名空间)

csharp 复制代码
// 为string 添加一个扩展方法(判断string是否为空||null)
public static bool IsEmpty(this string str)
{
	return string.IsNullOrEmpty(str);
}

7.字符串的嵌入值

$,用于代替string.Format("")

csharp 复制代码
Console.WriteLine("Hello, {0}! Today is {1}, it's {2:HH:mm} now.", name, date.DayOfWeek, date);
// String interpolation:
Console.WriteLine($"Hello, {name}! Today is {date.DayOfWeek}, it's {date:HH:mm} now.");

8.dynamic动态对象

.net4.0中引入了一个新类型 dynamic.该类型是一种静态类型,但类型为 dynamic 的对象会跳过静态类型检查.大多数情况下,该对象就像具有类型 object 一样.在编译时,将假定类型化为 dynamic 的元素支持任何操作

csharp 复制代码
dynamic dy = "string";
Console.WriteLine(dy.GetType());
//输出:System.String
dy = 100;
Console.WriteLine(dy.GetType());
//输出:System.Int32

9.运算符

csharp 复制代码
int gender = 1;
string str = gender == 1 ? "男" : "女";

合并运算符使用??表示,当进行转换时,如果可空类型的值为 null,则使用默认值。
int? intA = null;
int intB = 100;
intB = intA ?? 0;//此处intA为null,则将0赋值给intB

int? intC = 500;
intB = intC ?? 0;//此处intC不为null,则将500赋值给intB

引入了 ?. 的运算符,可帮助编写更少的代码来处理 null 检查
如果对象为NULL,则不进行后面的获取成员的运算,直接返回NULL
string str = "abcd";
string s1 = null;
Console.WriteLine(str?.Length);// 输出 4
Console.WriteLine(s1?.Length);// 输出空

10. 使用完毕后自动释放资源(Using || try finally)

using 是 C# 中用于 自动释放资源 的语法糖,适用于实现了 IDisposable 接口的对象(比如数据库连接、文件、网络流等)

为了节约资源,每次使用完毕后都要释放掉资源,其中可以使用Using和try finally来进行释放资源操作。需要注意的是使用Using释放资源的对象都必须继承IDisposable接口(MSDN)。非托管资源使用之后必须释放,而using()是使用非托管资源的最佳方式,可以确保资源在代码块结束之后被正确释放

using 是 C# 中用于 自动释放资源语法糖,适用于实现了 IDisposable 接口的对象(比如数据库连接、文件、网络流等)

csharp 复制代码
// try finally 写法
SqlConnection conn = null;
try
{
	conn = new SqlConnection("数据库连接字符串");
	conn.Open();
}
finally
{
	conn.Close();
	conn.Dispose();
}

// Using写法
using (SqlConnection conn=new SqlConnection("数据库连接字符串"))
{
      conn.Open();
}

如何知道所使用的对象能不能释放资源

那你怎么能知道所使用的对象能不能释放资源?

输入 对象名. 之后,会自动弹出一些提示的方法,如果有Dispose方法,那么就可以进行相应的释放。

csharp 复制代码
namespace Syntactic_sugar
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("正在运行代码1...");
            func myfunc = new func();
            try
            {
                Console.WriteLine("正在运行代码2...");
            }
            finally
            {
                myfunc.Dispose();
            }
            Console.WriteLine("正在运行代码3...");
        }
    }

    public class func : IDisposable
    {
        public void Dispose()
        {
            Console.WriteLine("释放资源");
        }
    }
}

==> 使用语法糖

 {
        static void Main(string[] args)
        {
            Console.WriteLine("正在运行代码1...");
            using (var myfunc = new func())
            {
                Console.WriteLine("正在运行代码2...");
            }
            Console.WriteLine("正在运行代码3...");
        }
    }

    public class func : IDisposable
    {
        public void Dispose()
        {
            Console.WriteLine("释放资源");
        }
    }
}

C# 3.0 语法糖

自动属性(Auto-Implemented Properties)

自动属性简化了属性的声明,省去了手动编写字段和属性方法的繁琐。

csharp 复制代码
// 以前的写法
private int _myVar;
public int MyProperty
{
     get { return _myVar; }
     set { _myVar = value; }
}
// 使用自动属性
public int MyProperty { get; set; }

对象初始化器(Object Initializers)

对象初始化器允许在声明对象时直接赋值属性,简化对象创建。

csharp 复制代码
// 以前的写法
Person p = new Person();
p.Name = "csframework.com";
p.Age = 18;

//使用对象初始化器
Person p = new Person { Name = "csframework.com", Age = 18 };

集合初始化器(Collection Initializers)

集合初始化器允许在声明集合时直接添加元素,简化集合创建。

csharp 复制代码
//以前的写法
List<int> numbers = new List<int>();
numbers.Add(1);
numbers.Add(2);

//使用集合初始化器
List<int> numbers = new List<int> { 1, 2 };

匿名类型(Anonymous Types)

匿名类型提供了一种简单的方式来创建包含多个属性的对象,而不需要显式定义类型。

csharp 复制代码
var person = new
{
    Name = "csframework.com",
    Age = 18
};
Console.WriteLine(person.Name);//输出"csframework.com"

Lambda 表达式

Lambda 表达式提供了一种简洁的方式来编写匿名方法。

csharp 复制代码
//使用匿名方法
Func<int, int> square = delegate (int x) { return x * x; };

//使用Lambda表达式
Func<int, int> square = x => x * x;

隐式类型局部变量(var)

隐式类型局部变量使用 var 关键字声明变量,由编译器推断其类型。

csharp 复制代码
var age = 10;//编译器推断为int
var name = "csframework.com";//编译器推断为string

C# 4.0 语法糖

参数默认值和命名参数

参数默认值允许为方法参数指定默认值。命名参数允许在调用方法时按名称指定参数,简化方法调用。

csharp 复制代码
//按顺序传递参数
test.DisplayGreeting("csframework.com", 23, "ZhuHai");

//调用时,可以使用命名参数来指定特定参数的值
test.DisplayGreeting(name: "csframework.com", city: "ZhuHai");

Console.ReadKey();

public static class test
{
    public static void DisplayGreeting(string name, int age = 35, string city = "ZhuHai")
    {
        //输出:Hello,csframework.com.You are35years old and live inZhuHai.
        Console.WriteLine($"Hello,{name}.You are{age}years old and live in{city}.");
    }
}

C# 5.0 语法糖

async 和 await

async 和 await 关键字简化了异步编程,提供了类似同步代码的编程体验。

csharp 复制代码
public async Task<string> FetchDataAsync()
{
    using (HttpClient client = new HttpClient())
    {
       string result = await client.GetStringAsync("https://www.example.com/test/data");
       return result;
    }
}

C# 6.0 语法糖

空值合并运算符(Null Coalescing Operator ??)

空值合并运算符提供了一种简洁的方式来处理可能为空的变量。

csharp 复制代码
string name = null;
string RegName = name ?? "csframework.com";
Console.WriteLine(RegName);//输出"csframework.com"

字符串插值(String Interpolation)

字符串插值提供了一种更简洁、更可读的字符串格式化方式。

csharp 复制代码
string name = "csframework.com";
int age = 18;
//Hello,my name is csframework.com and I am 18 years old.
string greeting = $"Hello,my name is {name} and I am {age} years old.";
Console.WriteLine(greeting);

空条件运算符(Null-Conditional Operator ?.)

空条件运算符简化了对可能为空的对象成员的访问。

csharp 复制代码
Employee employee = new Employee();
string departmentName = employee?.Department?.Name ?? "Unknown"; //输出Unknow
Console.WriteLine(departmentName);

Employee employee = null;
string departmentName = employee?.Department?.Name ?? "Unknown"; //输出Unknow
Console.WriteLine(departmentName);

扩展方法(Extensions)

扩展方法允许为现有类型添加新方法,而无需修改类型的定义。

csharp 复制代码
//使用扩展方法
var transform = new Transform();
transform.Hide();
transform.Show();

//使用现有的方法
transform.SetActive(false);
transform.SetActive(true);
Console.ReadKey();

//实体类
public class Transform
{
    public Transform SetActive(bool value)
    {
        Console.WriteLine(value);
        return new Transform();
    }
}

//扩展类
public static class TransformExtensions
{
    public static Transform Hide(this Transform transform) => transform.SetActive(false);

    public static Transform Show(this Transform transform) => transform.SetActive(true);

}

C# 7.0 语法糖

元组和解构(Tuples and Deconstruction)

元组提供了一种轻量级的数据结构,解构简化了元组元素的访问。

csharp 复制代码
//创建一个元组
var person = ("csframework.com", 18);

//解构元组:封装
var (name, age) = person;
Console.WriteLine($"Name:{name},Age:{age}");//Name:csframework.com,Age:18

模式匹配(Pattern Matching)

模式匹配增强了类型检查和转换的能力。

csharp 复制代码
object obj = 123;

//类型检查和转换
if (obj is int i)
{
    Console.WriteLine($"Integer:{i}");
}

C# 8.0 语法糖

using 声明

using 声明简化了资源管理,减少了嵌套。

csharp 复制代码
//C#8.0之前的写法
using (var stream = new FileStream("file.txt", FileMode.Open))
{
    //使用stream
    stream.Write();
}

//C#8.0及更高版本的写法
using var stream = new FileStream("file.txt", FileMode.Open);
//使用stream
stream.Write();

只读成员(Read-Only Members)

只读成员确保结构体成员不可变。

csharp 复制代码
public struct Point
{
    public double X { get; }
    public double Y { get; }

    //构造器:编译通过
    public Point(double x, double y)
    {
        X = x;
        Y = y;
    }

    //方法:编译不通过
    public void Set(double x, double y)
    {
        X = x;
        Y = y;
    }
}

默认接口实现(Default Interface Methods)

默认接口实现允许在接口中提供默认方法实现。

csharp 复制代码
public interface ILogger
{
    void Log(LogLevel level, string message)
    {
        //默认实现
        Console.WriteLine($"Log:{level}-{message}");
    }
}

public class ConsoleLogger : ILogger
{
    //可以选择不实现Log方法,使用默认实现
}

静态本地函数(Static Local Functions)

静态本地函数确保本地函数不捕获任何外围变量。

csharp 复制代码
//方法
void MyMethod()
{

    static void LocalFunction()
    {
        //这是一个静态本地函数
        Console.WriteLine("这是一个静态本地函数。");
    }

    //调用静态本地函数
    LocalFunction();
}

C# 9.0 语法糖

记录类型(Record Types)

记录类型简化了不可变数据结构的定义。

csharp 复制代码
var person = new Person("csframework.com", 18);
Console.WriteLine(person);//输出Person{Name=csframework.com,Age=18}

//定义记录类型
public record Person(string Name, int Age);

顶级语句(Top-Level Statements)

顶级语句简化了程序的入口点,省去了 Main 方法的定义。

csharp 复制代码
using System;
using System.Xml.Linq;

Console.WriteLine("Hello, csframework.com");
Console.ReadKey();

init 访问器(Init-Only Properties and Indexers)

init 访问器允许在对象初始化时设置属性,而初始化后属性变为只读。

csharp 复制代码
var point = new Point { X = 0.0, Y = 0.0 };
point.X = 100; //编译不通过

//结构
public struct Point
{
    public double X { get; init; }
    public double Y { get; init; }
}

模式和位置解构(Pattern Matching Enhancements for switch)

模式匹配增强了 switch 表达式的功能。

csharp 复制代码
    public static string GetSeason(DateTime date) => date.Month switch
    {
        12 or 1 or 2 => "Winter",
        3 or 4 or 5 => "Spring",
        6 or 7 or 8 => "Summer",
        9 or 10 or 11 => "Autumn",
        _ => "Unknown",//defaut 弃元
    }

C# 10.0 语法糖

目标类型的新表达式(Target-Typed New Expressions)

目标类型的新表达式简化了对象创建,省略了类型名。

csharp 复制代码
Point p = new(0.0, 0.0);

插值字符串增强(Interpolated String Enhancements)

插值字符串增强了表达式的灵活性,可以在插值表达式中调用方法。

csharp 复制代码
var name = "csframework.com";
//语法:$和{}
var message = $"Hello,{name.ToLower()}!";

结语

随着 C# 语言的发展,每个版本都为开发者带来了新的语法糖,使代码编写更加简洁、直观。这些语法糖不仅提高了代码的可读性,还提升了开发效率。通过本文的介绍,希望能帮助你更好地理解和应用这些语法糖,从而在实际开发中充分发挥它们的优势。

其他常用语法糖

表达式体属性

使用 => 运算符定义属性的 getter 或 setter。

csharp 复制代码
public string FullName => FirstName + " " + LastName;

隐式类型局部变量(var 关键字)

编译器根据初始化表达式推断变量的类型。

csharp 复制代码
var number = 42; // 推断为 int 类型

Lambda 表达式

定义匿名函数的简洁方式。

csharp 复制代码
Func<int, int, int> add = (x, y) => x + y;

表达式体成员

用于方法和委托。

csharp 复制代码
public int Square(int x) => x * x;

字符串插值

在字符串中嵌入变量或表达式的值。

csharp 复制代码
string message = $"Hello, {name}!";

空合并运算符(??)

当左侧操作数为 null 时,返回右侧操作数的值。

csharp 复制代码
string result = value ?? "Default Value";

名称空间别名

允许你为名称空间或类型定义别名,以简化代码中的引用。

csharp 复制代码
using System.Collections.Generic;
using List = System.Collections.Generic.List<int>; // 定义别名
List numbers = new List(); // 使用别名

弃元(Discard)

使用下划线 _ 作为占位符来表示不关心的变量值,这在解构赋值或模式匹配中特别有用。

csharp 复制代码
var (first, _) = GetTuple(); // 只关心第一个值,忽略第二个值

可空类型

使用可空类型(如 int?)可以表示值类型的空值,避免了使用默认值来表示空值的问题。

csharp 复制代码
int? age = null;
if (age.HasValue)
{
      // 处理非空值的情况
}

nameof 表达式

返回变量、类型或成员的名称作为字符串,主要用于异常消息、日志记录等。

csharp 复制代码
string name = "Alice";
Console.WriteLine(nameof(name)); // 输出 "name"

LINQ(Language Integrated Query)

允许你在 C# 中直接编写查询语句,而无需使用额外的查询语言。

csharp 复制代码
var query = from p in people
            where p.Age > 18
            select p.Name;

条件编译指令

使用如 #if, #else, #endif 等预处理指令,可以根据不同的编译条件包含或排除代码块。这对于跨平台开发或调试非常有用。

csharp 复制代码
#if DEBUG
    Console.WriteLine("Debug mode is enabled.");
#endif
相关推荐
qq_12498707532 小时前
基于SpringBoot学生学习历史的选课推荐系统的设计与实现(源码+论文+部署+安装)
java·spring boot·后端·学习·毕业设计·毕设
武藤一雄2 小时前
C#:进程/线程/多线程/AppDomain详解
后端·微软·c#·asp.net·.net·wpf·.netcore
华仔啊2 小时前
RabbitMQ 如何保证消息不丢失和不重复消费?掌握这 4 个关键点就够了
java·后端·rabbitmq
学历真的很重要3 小时前
PyTorch 机器学习工作流程基础 - 完整教程
人工智能·pytorch·后端·python·深度学习·机器学习·面试
曹牧3 小时前
在C#中,string和String
开发语言·c#
执笔诉情殇〆3 小时前
使用AES加密方法,对Springboot+Vue项目进行前后端数据加密
vue.js·spring boot·后端
码事漫谈4 小时前
单链表与双链表专题详解
后端
Lear4 小时前
【JavaSE】NIO技术与应用:高并发网络编程的利器
后端