C#十种语法糖

Posted .NET开发菜鸟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#十种语法糖相关的知识,希望对你有一定的参考价值。

语法糖

指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。
需要声明的是“语法糖”这个词绝非贬义词,它可以给我们带来方便,是一种便捷的写法,编译器会帮我们做转换,而且可以提高开发编码的效率,在性能上也不会带来损失。

一、自动属性

以前:手写私有变量+公有属性
现在:声明空属性,编译器自动生成对应私有成员字段。

写法:输入prop ,连续按两次tab键,自动生成属性。

 1         /// <summary>
 2         /// 自动属性
 3         /// </summary>
 4         public string Name { get; set; }
 5 
 6         /// <summary>
 7         /// 传统属性写法
 8         /// </summary>
 9         private string _LoginName;
10 
11         public string LoginName
12         {
13             get { return _LoginName; }
14             set { _LoginName = value; }
15         }

 二、隐式类型(var)

var定义变量有以下四个特点:
程序员在声明变量时可以不指定类型,由编译器根据值来指定类型
1、必须在定义时初始化
2、一旦初始化完成,就不能再给变量赋与初始值不同类型的值了
3、var要求是局部变量
4、使用var定义变量和object不同,它在效率上和使用强类型方式定义变量完全一样

注意:
a.隐式类型在定义时必须初始化
例如:var name; 错  var name="Tom";正确
b.可以用同类型的其他隐式类型变量来初始化新的隐式类型变量
例如:var v=1;
      var v2=v;
c.也可以用同类型的字面量来初始化隐式类型变量
例如: var v3="hello";
      v3="world";
d.隐式类型局部变量还可以初始化数组而不指定类型
例如: var array=new int[]{1,2,3,4,5}; (注意:赋值运算符左边没有方括号)
e.编译器可以根据变量的初始值“推断”变量的类型
例如: var number=0;  编译后就变成了  int number =0;

三、参数默认值和命名参数

    C#方法的可选参数是.net 4.0最新提出的新的功能,对应简单的重载可以使用可选参数和命名参数混合的形式来定义方法,这样就可以很高效的提高代码的运行效率
    设计一个方法的参数时,可以部分或全部参数分配默认值。调用其方法时,可以重新指定分配了默认值的参数,也可以使用默认值。重新指定分配默认值的参数时,可以显式地为指定参数名称赋值;隐式指定的时候,是根据方法参数的顺序,靠C#编译器的推断。

使用的指导原则:
1、可以为方法和有参属性指定默认值
2、有默认值的参数,必须定义在没有默认值的参数之后
3、默认参数必须是常量
4、ref和out参数不能指定默认值

 1  public class User
 2     {
 3         /// <summary>
 4         /// 自动属性
 5         /// </summary>
 6         public string Name { get; set; }
 7 
 8         public string LoginName { get; set; }
 9 
10         public int Age { get; set; }
11 
12         public string  Address { get; set; }
13 
14         public string  Password { get; set; }
15 
16         //构造函数重载
17         public User(string name)
18         {
19             this.Name = name;
20         }
21 
22         public User(string name,string loginName)
23         {
24             this.Name = name;
25             this.LoginName = loginName;
26         }
27 
28         /// <summary>
29         /// 默认参数
30         /// </summary>
31         /// <param name="name"></param>
32         /// <param name="loginName"></param>
33         /// <param name="age"></param>
34         /// <param name="address"></param>
35         /// <param name="password"></param>
36         public User(string name,string loginName,int age,string address="上海",string password="1234")
37         {
38             this.Name = name;
39             this.LoginName = loginName;
40             this.Age = age;
41             this.Address = address;
42             this.Password = password;
43         }
44     }
45 
46 使用默认值参数和命名参数
47  class Program
48     {
49         static void Main(string[] args)
50         {
51             //参数默认值:可以给参数赋值也可以使用参数默认值
52             //1、使用默认值
53             User user = new User("小明","xiaoming",27);
54             Console.WriteLine(user.Address);//输出默认值:上海
55 
56             //2、给参数赋值
57             User user2 = new User("小红", "xiaohong", 28,"北京");
58             Console.WriteLine(user2.Address);//输出:北京
59 
60             //命名参数:使用默认值参数的时候,指定参数的名称,命名参数要写在所有固定参数的后面
61             //好处:适用于有多个默认值参数的情况,根据命名参数,只修改需要修改的默认值
62             //使用命名参数只修改密码
63             User user3 = new User("小红", "xiaohong", 28,password:"5678");
64             Console.WriteLine(user3.Password);//输出:5678
65 
66             Console.ReadKey();
67         }
68     }

输出结果:

四、对象初始化器和集合初始化器

 1  class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5 
 6             //传统的初始化对象的方式
 7             User zjl = new User();
 8             zjl.Name = "周杰伦";
 9             zjl.phone = "12345678956";
10 
11             //使用对象初始化器:{},使用对象初始化器,必须提供一个无参的构造函数,可以只给部分属性初始化
12             User xiaohong = new User()
13             {
14                 Name = "小红",
15                 phone = "1232154566",
16                 Address = "上海"
17             };
18 
19             Console.WriteLine("姓名:"+xiaohong.Name);//输出:小红
20 
21             //集合初始化器
22             List<User> listUser = new List<User>()
23             {
24                 xiaohong,
25                 new User(){Name="张三",Password="1234",Age=12,DeptId="0001"},
26                 new User(){Name="张四",Password="1234",Age=16,DeptId="0002"},
27                 new User(){Name="张五",Password="1234",Age=29,DeptId="0003"},
28                 new User(){Name="张六",Password="1234",Age=18,DeptId="0001"},
29                 new User(){Name="张七",Password="1234",Age=12,DeptId="0001"}
30             };
31             Console.ReadKey();
32         }
33     }

 五、匿名类和匿名方法

 

匿名类型
有时候你定义的类只是用来封装一些相关的数据,但并不需要相关联的方法、事件和其他自定义的功能。同时,这个类仅仅在当前的应用程序中使用,而不需要在项目间重用。你所需要的只是一个“临时的”类型,现在来看看这个类的定义
internal class oneClass
{
   //定义若干私有数据成员
   //通过属性来封装每个数据成员
}

构建上面的类虽然说不上有多难,但是如果这个类有很多数据成员的话,那么还是要消耗相当时间的。C#3.0提供了匿名类型来轻松完成这个工作。
现在定义一个匿名对象来表示一个人
var aPeople=new {pName="张三",pAge=26,pSex="男"};
现在我们就可以使用属性语法获取和设置对象的各个变量
aPeople.pAge=29;
Console.WriteLine("{0} is {1}years old",aPeople.pName,aPeople.pAge);
匿名类型的嵌套
    刚刚我们定义了表示一个人的匿名类型,现在我们定义一个表示雇员的嵌套匿名类型:
    var Aemployee=new {
        JoinDate="2012-09-23",
        aPeople=new {pName="张三",pAge=26,pSex="男"},
        title=Manager
    };

匿名类型的限制:
1、匿名类型不支持事件、自定义方法和自定义重写
2、匿名类型是隐式封闭的
3、匿名类型的实例创建只使用默认构造函数
4、匿名类型没有提供可供控制的类名称(使用var定义的)

匿名方法
普通方法定义方式,因为方法的存在是为了复用一段代码,所以一般会给方法取个名字,这个方法的引用就可以通过“方法名”调用
匿名方法:
但是有的方法,不需要复用,仅仅是使用一次就够了,所以不需要方法名,这种方法就叫做匿名方法。
匿名方法必须结合委托使用。(潜在的意思就是:尽管没有方法名了,但方法的指针还是存放了某个委托对象中)
注意:
1、在编译后,会为每个匿名方法创建一个私有的静态方法,然后将此静态方法传给委托对象使用
2、匿名方法编译后会生成委托对象,生成方法,然后把方法装入委托对象,最后赋值给声明的委托变量
3、匿名方法可以省略参数,编译的时候会自动为这个方法按照委托签名的参数添加参数

 1   public class Test
 2     {
 3         public static void TestFive()
 4         {
 5             //匿名类型:只能使用一次,仅能在当前的项目中使用
 6             var aPeople = new { pName = "张三", pAge = 26, pAddress = "美国" };
 7             //嵌套匿名类型
 8             var aEmployee = new
 9             {
10                 JionDate = DateTime.Now,
11                 Salary = 8000,
12                 aPeople = new { pName = "张三", pAge = 26, pAddress = "美国" }
13             };
14 
15             Console.WriteLine(aEmployee.aPeople.pName);//输出:张三
16 
17             Console.ReadKey();
18         }
19 
20         public static void Test()
21         {
22             //不能使用匿名类型aPeople,aPeople是局部
23             Console.WriteLine(aPeople.pName);//错误
24         }
25     }

匿名方法


 1 class Program
 2     {
 3         /// <summary>
 4         /// 声明委托
 5         /// </summary>
 6         /// <param name="s"></param>
 7         delegate void Printer(string s);
 8         public delegate void PrintEmployee(User u);
 9 
10         static void Main(string[] args)
11         {
12             //匿名方法:必须结合委托使用
13             Printer p = delegate(string s)
14             {
15                 Console.WriteLine(s);
16             };
17             //使用匿名方法
18             p("Hello World");
19 
20             List<User> listUser = new List<User>()
21             {
22                 new User(){Name="张三",Password="1234",Age=12,DeptId="0001"},
23                 new User(){Name="张四",Password="1234",Age=16,DeptId="0002"},
24                 new User(){Name="张五",Password="1234",Age=29,DeptId="0003"},
25                 new User(){Name="张六",Password="1234",Age=18,DeptId="0001"},
26                 new User(){Name="张七",Password="1234",Age=12,DeptId="0001"}
27             };
28 
29             //匿名方法只使用一次
30             ChangeUserPwd(listUser, delegate(User u) {
31 
32                 Console.WriteLine(u.Name+"的新密码是:"+u.Password);
33             });
34             //使用Lambda表达式
35             ChangeUserPwd(listUser, u=>
36             {
37                 Console.WriteLine(u.Name + "的新密码是:" + u.Password);
38             });
39             Console.ReadKey();
40         }
41 
42         /// <summary>
43         /// 批量修改用户的密码并输出修改以后的密码
44         /// </summary>
45         /// <param name="list"></param>
46         /// <param name="callback"></param>
47         public static void ChangeUserPwd(List<User> list, PrintEmployee callback)
48         {
49             int i = 0;
50             foreach (User u in list)
51             {
52                 u.Password = u.Password + i.ToString();
53                 i += 2;
54                 callback(u);
55             }
56         }        
57     }

 


 六、扩展方法

为什么要有扩展方法,就是为了在不修改源码的情况下,为某个类增加新的方法。
语法:
定义静态类,并添加public的静态方法,第一个参数代表扩展方法的扩展类。它必须放在一个非嵌套、非泛型的静态类中(的静态方法);它至少有一个参数;第一个参数必须附加this关键字;第一个参数不能有任何其他修饰符(out/ref).第一个参数不能是指针类型。
注意:
1、C#只支持扩展方法,不支持扩展属性、扩展事件等;
2、方法名无限制,第一个参数必须带this,表示要扩展的类型;
3、扩展方法的命名空间可以使用namespace System,但不推荐;
4、定义扩展方法的类必须是静态类;
5、扩展方法虽然是public的静态方法,但是生成以后是实例方法,使用时需要先实例化对象,通过对象.方法名进行调用扩展方法;

 1 /// <summary>
 2     /// 静态类:对Convert进行扩展,增加一个将string转换成int的方法
 3     /// </summary>
 4     public static class ConvertExtension
 5     {
 6         /// <summary>
 7         /// 静态方法:this 表示针对this后面的类型进行扩展
 8         /// </summary>
 9         /// <param name="s"></param>
10         /// <returns></returns>
11         public static int ConvertToInt(this Convert convert,string s)
12         {
13             int i;
14             if (int.TryParse(s, out i))
15             {
16                 return i;
17             }
18             else
19             {
20                 return 0;
21             }
22         }
23     }
24 
25 class Program
26     {
27         static void Main(string[] args)
28         {
29             //使用扩展方法:扩展方法虽然是public的静态方法,但是生成以后是实例方法,使用时需要先实例化对象,通过对象.方法名进行调用扩展方法
30             //扩展方法所在命名空间和使用代码的命名空间必须相同 扩展方法必须是静态类
31             Convert convert = new Convert();
32             int i= convert.ConvertToInt("abc");
33 
34             Console.WriteLine(i);//输出:0
35 
36             //方法2
37             int j= ConvertExtension.ConvertToInt(convert, "2");
38             Console.WriteLine(j);//输出:2
39 
40             Console.ReadKey();
41         }
42     }

七、内置泛型委托

Action<T>
可以使用Action<T>委托以参数形式传递方法,而不用显示声明自定义的委托。封装的方法必须与此委托定义的方法签名相对应,也就是说,封装的方法必须具有一个通过值传递给它的参数,并且不能有返回值。
通常,这种方法用于执行某个操作。

 1 /// <summary>
 2     /// List扩展方法
 3     /// </summary>
 4     public static class ListExtend
 5     {
 6         //声明自定义泛型委托
 7         public delegate void PrintT<T>(T t);
 8 
 9         public static void TEach<T>(this List<T> list, PrintT<T> pt)
10         {
11             foreach (T t in list)
12             {
13                 pt(t);
14             }
15         }
16     }
17 
18 
19 class Program
20     {
21         
22         static void Main(string[] args)
23         {
24             List<User> listUser = new List<User>()
25             {
26                 new User(){Name="张三",Password="1234",Age=12,DeptId="0001"},
27                 new User(){Name="张四",Password="1234",Age=16,DeptId="0002"},
28                 new User(){Name="张五",Password="1234",Age=29,DeptId="0003"},
29                 new User(){Name="张六",Password="1234",Age=18,DeptId="0001"},
30                 new User(){Name="张七",Password="1234",Age=12,DeptId="0001"}
31             };
32 
33             List<Dept> listDept = new List<Dept>()
34             {
35                 new Dept(){DeptId="0001",DeptName="人事部",PepNum=10},
36                  new Dept(){DeptId="0002",DeptName="财务部",PepNum=7},
37                   new Dept(){DeptId="0003",DeptName="行政部",PepNum=15}
38             };
39 
40 
41             #region 使用自定义委托
42             
43             //打印所有用户信息
44             listUser.TEach(PrintUser);
45 
46            

以上是关于C#十种语法糖的主要内容,如果未能解决你的问题,请参考以下文章

C#语法糖系列 —— 第一篇:聊聊 params 参数底层玩法

自动扩展 C# 3 语法糖

C#语法糖 Null 条件运算符 ?.

C#语法糖系列 —— 第一篇:聊聊 params 参数底层玩法

C#语法糖空合并运算符??和空合并赋值运算符 ??=

c#语法糖汇总