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属性,但是我们仍然能正常使用这些函数的原因了。

 

 

 

 

 

posted @ 2020-03-25 09:53  好Wu赖  阅读(582)  评论(0编辑  收藏  举报