C# 语法糖
语法糖:指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。
它可以给我们带来方便,是一种便捷的写法,编译器会帮我们做转换;而且可以提高开发编码的效率,在性能上也不会带来损失。
语法糖——它不甜吗
它好甜呐☻☺
$符号、对象初始值设定项、元组、Linq、Null检查符?.、可爱的var、扩展方法、yield关键字
1.$符号【字符串插值C#6新特性】的用法
$符号的作用相当于对String.format()的简化
//使用Format的写法 string str2 = string.Format("my name is {0},my age is {1}.", name, age); //使用$语法糖的写法 string str3 = $"my name is {name},my age is {age}.";
2. 对象初始值设定项 和 匿名对象 ,类型实例化的语法糖
利用对象初始值设定项语法,你可为构造函数指定参数或忽略参数(以及括号语法)。
//对象初始化器 Person p = new Person { Name = "andy", Age = 24 }; //匿名对象 var p2 = new { Name = "dimo", Age = 24 }; Console.WriteLine(p.Name); Console.WriteLine(p2.Name); Cat cat = new Cat { Age = 10, Name = "Fluffy" }; Cat sameCat = new Cat("Fluffy"){ Age = 10 };
声明一个List并给list赋初始值——初始值设定项
List<string> list = new List<string> {"def","OK"};
3、元组
//结构Struct public struct ValueTuple<T1, T2, T3>: IEquatable<ValueTuple>, IStructuralEquatable, IStructuralComparable, IComparable, IComparable<ValueTuple>, IValueTupleInternal, ITuple //类class public class Tuple<T1> : IStructuralEquatable, IStructuralComparable, IComparable, ITupleInternal, ITuple
数组合并了相同类型的对象,而元组合并了不同类型的对象。
ValueTuple<int,int> s = (1, 3);//直接使用()声明最方便 var svar = (1, 3);//括号声明。 Tuple<int> ne = new Tuple<int>(2);//new 或静态方法Create Tuple<int> creat = Tuple.Create<int>(2);//静态方法Create
4. 集合类各个项的操作Linq。
我们为了逐个处理集合中的项,需要这么写:
foreach (string item in list) { Console.WriteLine(item); }
现在不需要了,这样就可以了
list.ForEach(a => Console.WriteLine(a));
在语法糖的光辉照耀下,可以这样:Linq 或 对应方法。
public class Program { public static void Main() { List<string> Sizes = new List<string> { "L", "XL", "XXL" }; Sizes.ForEach(x => Console.WriteLine(x)); //更多使用方法(包括但不限于这些 ,自己挖吧,伙伴们!): //确定“XL”是否在集合中 var r1 = Sizes.Contains("XL"); //确定集合中是否包含与条件匹配的元素 var r2 = Sizes.Exists(x => x == "XL"); //返回集合项中包含“X”的第一个元素 var r3 = Sizes.Find(x => x.Contains("X")); } }
5.??、 ?、 ?: 、?.
1. 可空类型修饰符(?)
2. 三元(运算符)表达式(?: )
例如:x?y:z 表示如果表达式x为true,则返回y;
如果x为false,则返回z,是省略if{}else{}的简单形式。
3. 空合并运算符(??)——相当于三目运算符,
判断是否不为空 x??y 相当于 x!=null?x:y
最大的用处是将可空类型的值赋给对应的基元类型进行简化。可空类型不可强转对应C#内置类型。
int? i = 123; int j = i ?? 0;
4.NULL检查运算符(?.) 替代原来的 .
?[]是索引器的Null检查用法。
如果 a 的计算结果为 null,则 a?.x 或 a?[x] 的结果为 null。
如果 a 的计算结果为非 null,则 a?.x 或 a?[x] 的结果将分别与 a.x 或 a[x] 的结果相同。
int? firstX = null; if (points != null) { var first = points.FirstOrDefault(); if (first != null) firstX = first.X; }
正确倒是正确了,代码取变得难读多了。在C# 6.0中,引入了一个 ?. 的运算符,前面的代码可以改成如下形式:
int? firstX = points?.FirstOrDefault()?.X;
从这个例子中我们也可以看出它的基本用法:如果对象为NULL,则不进行后面的获取成员的运算,直接返回NULL
6. 可爱的var
var的意义时不必写声明的类型,编译器会根据后面对var的赋值判断它的类型,var的类型一旦确认就不能再改变,它只能作为局部变量使用,不能用做字段也不能用做参数声明。
例如:
var writer = new StreamWriter(path); for(var i=0;i<100;i++){}
7. 传说中的扩展方法
1、 扩展类必须为静态类,扩展方法必须为静态方法【静态类中只能有静态方法】。
2、扩展方法的第1个形参开头必须使用 “this” 关键字然后再填写扩展的目标类。
3、如果需要接收参数则从第2个参数开始算起,第1个参数在真正调用方法时是隐藏的。
在c#3.5时引入了扩展方法,我们可以在不修改类源码的情况下给类增加实例方法,这个很有意义。它的实质也是一种语法糖的实现
例如我们给String类扩展一个IsNumber的方法:
public static class StringExt { static private Regex regexNumber = new Regex("\\d+"); static public bool IsNumber(this string input) { if (string.IsNullOrEmpty(input)) { return false; } return regexNumber.IsMatch(input); } }
扩展方法有两种调用方式:
扩展方法:
public static class ItemsManagerComponentHelper { public static ItemInfo getItemById(this ItemsManagerComponent self, long itemId)
调用:
ItemInfo newFashion0 = ItemsManagerComponentHelper.getItemById(itemsManagerComponent,10); ItemInfo newFashion = itemsManagerComponent.getItemById(10);
————————————————
参考链接:https://blog.csdn.net/kone0611/article/details/76056318
▲
▲在 java 中没有这样的东西,一个类一旦是 final 的 ,这个类就不能再被添加方法, 但是 C# 能够做到,可以给 sealed 类添加新的方法,这点我还是比较喜欢 c# 的。这就是 C# 中的扩展方法。
那么什么情况下我们才需要去给一个类写扩展方法呢?
系统自带的类型,我们无法去修改;
修改源代码需要较大的精力,而且可能会带来错误;
我们只是需要一个或者较少的几个方法,修改源代码费时费力;
被扩展的类是 sealed 的,不能被继承;(就算不是 sealed 的,我们也不能因为需要一个方法而去写一个子类,这样不是面向对象)
▲下面是扩展方法的三个要素:(也算是语法规则)
扩展方法必须处于一个静态类中;
扩展方法必须是一个静态方法;
扩展方法的参数列表必须以 this 开头,this 后面紧跟的是被扩展类,然后才是方法需要的参数;
▲下面写一下扩展方法的特点:
this 关键字紧跟着的不是参数,而是调用者,调用者后面的参数才是扩展方法真正的参数,在调用时必须传递;
如果被扩展的类中的实例方法和扩展方法的方法签名相同(扩展方法中方法的签名应该要去掉 this 和调用者参数),则优先调用本类中的实例方法;
被扩展类(可以是普通类,也可以是接口抽象类)的子类对象可以直接调用父类的扩展方法,也就是说子类也继承了父类的扩展方法;
这点算是第 3 点的补充,只有被扩展类的本类对象或者子类对象,才能调用扩展方法;
8. yield关键字定义迭代器方法,返回值必须是IEnumberable等集合接口
yield return:
先看下面的代码,通过yield return实现了类似用foreach遍历数组的功能,说明yield return也是用来实现迭代器的功能的。执行完第一个yield再向下执行。
using static System.Console; using System.Collections.Generic; class Program { //一个返回类型为IEnumerable<int>,其中包含三个yield return //yield return 定义迭代器方法。 public static IEnumerable<int> enumerableFuc() { yield return 1; yield return 2; yield return 3; } static void Main(string[] args) { //通过foreach循环迭代此函数 foreach(int item in enumerableFuc()) { WriteLine(item); } ReadKey(); } } 输出结果: 1 2 3
yield break是用来终止迭代的。
2.只能使用在返回类型必须为 IEnumerable、IEnumerable<T>、IEnumerator 或 IEnumerator<T>的方法、运算符、get访问器中。
这也能说明yield关键字其实是一种语法糖,最终还是通过实现IEnumberable<T>、IEnumberable、IEnumberator<T>和IEnumberator接口实现的迭代功能。
3.编译的时候自动生成了一个新的类,方法返回了这个新的类。它继承了IEnumerable、IEnumerable<T>、IEnumerator 或 IEnumerator<T>,这时我们应该已经能猜到这个新的类就是我们没有实现对应的IEnumerator的MoveNext(),和Current属性,但是我们仍然能正常使用这些函数的原因了。