C#语法糖,甜过初恋

偶然翻看了n年前自己写的几篇技术博文,真真切切切切实实实实在在有恍如隔世之感。当年那么晦涩枯燥的汇编代码亦能写的行云流水般,如今却几乎看不懂了,让美貌与智慧为化身的作者君那颗强大的玻璃心飘过一丝蛋蛋的忧伤。于是乎,不仅感叹计算机语言技术的发展速度,以及对生产效率带来的影响,其中C#的语法糖具有相当突出的代表性。语法糖比那些貌美如花嗲的掉渣的程序员鼓励师实用多了。

趁月落乌啼夜黑风高好下手,赶紧把当前的C#语法糖整理和汇总一下,第一温故知新,第二备忘,第三给需要的人参考,不足之处欢迎批评斧正,和谐社会禁止拍砖。魏滔序原创,欢迎转载但请注明出处。

先看一段来自百度百科的解释:

语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。

.Net从2.0到3.0到3.5底层CLR并没有做更新,没有添加任何新的IL指令,所以C#从2.0到3.0中所有的特性都是语法糖,就算从1.0到2.0,也只有一个泛型不是语法糖,其余的新特性也都是如此,但是每一次C#发布新特性的时候我们不得不为之而鼓舞,为之而喝彩。新的语法可以酿造更好的编程风格,一些难以实现的方面也轻而易举了。

题外话:忽然赶脚CSDN的编辑器比n年前一成不变的难用好用多了,此处给个赞(宇宙全无敌黄金广告位招租),下面言归正传。



属性(Property)

常规写法如下:

    public class Product
    {
        private string _name;
        public Product()
        {
            _name = "白色经典长袖衬衫";
            //或者
            //Name = "白色经典长袖衬衫";
        }
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
    }

或者如下:

    public class Product
    {
        private string _name = "白色经典长袖衬衫";
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
    }

两者的区别只是赋初始值时机不同,代码的冗余量不相上下,在C#3.0后,语法做了如下的简化处理:

    public class Product
    {
        public Product()
        {
            Name = "白色经典长袖衬衫";
        }
        public string Name { get; set; }
    }

属性声明一行足矣,代码冗余量大幅减少,当然也不会因此失去灵活性,比如给get或set指定访问限制符:

public string Name { protected internal get; set; }

然而,善解人衣的MS工程师们认为这样还是甜不过初恋,在C#6.0中又撒了一把糖(自动属性初始化器),且看:

    public class Product
    {
        public string Name { get; set; } = "白色经典长袖衬衫";
    }

从开始的那么一大坨变成一行,多么令人陶醉的写法。需要注意的是在C#6.0中,除了以上方法直接赋值外,在构造函数中也可以为只读属性赋值,之前。。。那是不允许滴:

    public class Product
    {
        public string Name { get; }
        public Product()
        {
            Name = "白色经典长袖衬衫";
        }
    }

但是,如果在声明中已经赋值,那么在构造函数中依然不允许,编译器是位多么称职的保姆啊啊啊。

    public class Product
    {
        public string Name { get { return "白色经典长袖衬衫"; } }
        //C#6.0中还可以使用属性表达式为只读属性赋值,如下行代码:
        //public string Name => "白色经典长袖衬衫";
        public Product()
        {
            Name = "白色经典长袖衬衫"; //编译器说了,不要酱紫嘛
        }
    }

这糖,甜过初恋。



可空类型(T?)

可空类型可以表示基础类型的所有值,另外还可以表示 null 值。可空类型可通过下面两种方式中的一种声明:

System.Nullable<T> variable
//或
T? variable

T 是可空类型的基础类型。T 可以是包括 struct 在内的任何值类型;但不能是引用类型。可空类型有一个HasValue的bool类型的只读属性,当该属性为true的时候,那么该值为非空实例,可以正常访问该值的Value。如果HasValue的属性为false的时候,那么访问该值的Value导致异常。

    public class Program
    {
        public static void Main()
        {
            int? a = null;
            int? b = 500;
            int? c;
            if (a.HasValue)
            {
                c = a.Value;
            }
            else
            {
                c = b;
            }
        }
    }

注意,在C#6.0中对所有可以为null的数据类型做了增强,下面的代码如果name为null时,r的值也为null:

    public class Program
    {
        public static void Main()
        {
            string name = "白色经典长袖衬衫";
            int? r = name?.Length;
        }
    }

这糖,甜过初恋。



条件运算符(?:)

根据 Boolean 表达式的值返回两个值之一。 下面是条件运算符的语法。

condition ? first_expression : second_expression;

condition 的计算结果必须为 true 或 false。 如果 condition 为 true,则将计算 first_expression 并使其成为结果。 如果 condition 为 false,则将计算 second_expression 并使其成为结果。 只计算两个表达式之一。

first_expression 和 second_expression 的类型必须相同,或者必须存在从一种类型到另一种类型的隐式转换。

对于上面的可空类型的示例代码可以简化成:

    public class Program
    {
        public static void Main()
        {
            int? a = null;
            int? b = 500;
            int? c = a.HasValue ? a.Value : b;
        }
    }

这糖,甜过初恋。



空接合操作符(??)

空接合操作符(null-coalescing operator),要获取两个操作数。假如左边的操作数不是null,就返回这个操作数的值。如果左边的操作数是null,就返回右边这个操作数的值。利用空接合操作符可以方便的设置变量的默认值。它的另一个妙处在于,它既能用于引用类型,也能用于可空值类型。

    public class Program
    {
        public static void Main()
        {
            int? a = null;
            int? b = 500;
            int? c = a ?? b;
            //上面代码等价于
            //int? c = a.HasValue ? a.Value : b;
        }
    }

这糖,甜过初恋。



委托(delegate)

常规写法如下:

    public delegate void DemoDelegate(string name);
    public class Program
    {
        public static void Main()
        {
            ReceiveDelegateArgs(new DemoDelegate(DelegateFunction)); //声明函数
        }
        public static void ReceiveDelegateArgs(DemoDelegate demoDelegate)
        {
            demoDelegate("白色经典长袖衬衫");
        }
        //声明的委托调用函数
        public static void DelegateFunction(string name)
        {
            Console.WriteLine(name);
        }
    }

C#2.0引入了匿名委托的概念,简化了调用函数的声明,代码自然简化不少:

    public delegate void DemoDelegate(string name);
    public class Program
    {
        public static void Main()
        {
            ReceiveDelegateArgs(delegate (string name) //匿名委托
            {
                Console.WriteLine(name);
            });
        }
        public static void ReceiveDelegateArgs(DemoDelegate demoDelegate)
        {
            demoDelegate("白色经典长袖衬衫");
        }
    }

然而,C#3.0出现的Lambda表达式又进一步简化了代码冗余量,显然看起来没那么忧伤了:

    public delegate void DemoDelegate(string name);
    public class Program
    {
        public static void Main()
        {
            ReceiveDelegateArgs(x => Console.WriteLine(x)); //Lambda表达式
        }
        public static void ReceiveDelegateArgs(DemoDelegate demoDelegate)
        {
            demoDelegate("白色经典长袖衬衫");
        }
    }

这糖,甜过初恋。



拉姆达(Lambda)

既然上面提到了Lambda,那就说说这个语法神器。C#的Lambda表达式的本质是匿名函数,在C#6.0的Lambda表达式可以当作函数体使用:

    public class Program
    {
        public static void Main()
        {
            Print("白色经典长袖衬衫");
        }
        public static void Print(string name) => Console.WriteLine(name);
    }

但也仅适合一条语句的情况,多条语句就要单独封装了,比如:

    public class Program
    {
        public static void Main()
        {
            Print("白色经典长袖衬衫", "XXL");
        }
        public static void Print(string name, string size) => Prints(name, size);
        public static void Prints(string name, string size)
        {
            //WriteLine可以输出多值,下面仅为表示多行语句
            Console.WriteLine(name);
            Console.WriteLine(size);
        }
    }

这糖,甜过初恋。



var类型

var类型出现于.Net3.5,其目的是弱化类型的定义。var可替代任何类型,编译器会根据上下文来判断你想用的真正类型,一旦初始完成就不能再给其赋与初始化类型不同的值了。var与object不同,var在效率上和使用强类型方式定义的变量完全一样,var只能作为局部变量使用,不能用做字段也不能用做参数声明。

    var name = "白色经典长袖衬衫";   // string
    var size = 160;                // int
    var color = ConsoleColor.Blue; // ConsoleColor

这糖,甜过初恋。



匿名类

这货在EF、JSON序列化、Linq to SQL中很好用:

    public class Program
    {
        public static void Main()
        {
            var product = new
            {
                Name = "白色经典长袖衬衫",
                Size = "XXL"
            };
        }

    }

这糖,甜过初恋。



集合初始化

通常,对集合类型的对象的初始赋值是酱紫的:

    public class Product
    {
        public Product()
        {
            IList<string> Sizes = new List<string>();
            Sizes.Add("L");
            Sizes.Add("XL");
            Sizes.Add("XXL");
        }
    }

自从有了语法糖,腰不酸了腿不疼了代码也可以写成这样了:

    public class Product
    {
        public Product()
        {
            IList<string> Sizes = new List<string> { "L", "XL", "XXL" };
            //或数组
            //string[] Sizes = new string[] { "L", "XL", "XXL" };
        }
    }

一口气能爬19楼不费劲,甚至在C#6.0中的Dictionary可以这样写了(学名叫“带索引的对象初始化器”):

    public class Product
    {
        public Product()
        {
            Dictionary<string, string> Colors = new Dictionary<string, string>()
            {
                ["Red"] = "红色",
                ["Blue"] = "蓝色"
            };
        }
    }

这糖,甜过初恋。



集合操作

通常遍历集合中的项的代码是这样写的:

    public class Program
    {
        public static void Main()
        {
            List<string> Sizes = new List<string> { "L", "XL", "XXL" };
            foreach (string size in Sizes)
            {
                Console.WriteLine(size);
            }
        }
    }

在语法糖的光辉照耀下,可以这样:

    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"));
        }
    }

这糖,甜过初恋。



using VS try finally

在C#和其他托管语言中,没有自动、决定性的析构方式,而是有一个垃圾收集器,它会在未来的某个时刻释放资源。它是非决定性的,因为我们不能确定这个过程在什么时候发生,通常使用try fiannaly来实现资源释放,但using用起来更简洁高效。例如:

    public class Program
    {
        public static void Main()
        {
            Stream stream = null;
            try
            {
                stream = new MemoryStream();
                //......
            }
            catch
            {
                throw;
            }
            finally
            {
                if (stream != null)
                    stream.Dispose();
            }
        }
    }

以上代码等价于:

    public class Program
    {
        public static void Main()
        {
            using (var stream = new MemoryStream())
            {
                //......
            }
        }
    }

这糖,甜过初恋。



类实例化

先看下这个简单的类:

    public class Product
    {
        public string Name { get; set; }
        public string Size { get; set; }
    }

这个类有两个属性,没有声明构造函数,可以通过下面的方法一步完成对象的实例化和初始赋值:

    public class Program
    {
        public static void Main()
        {
            var product = new Product()
            {
                Name = "白色经典长袖衬衫",
                Size = "XXL"
            };
        }
    }

这糖,甜过初恋。



扩展方法

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

    public static class MyExtensions
    {
        static public bool IsUpper(this string input)
        {
            return input == input.ToUpper();
        }
    }

    public class Program
    {
        public static void Main()
        {
            var name = "ABC";
            var r = name.IsUpper();
        }
    }

这糖,甜过初恋。



字符串嵌入值(String.Format)

简单来说就是将指定字符串中的每个格式项替换为相应对象的值的文本等效项,比用拼接字符串的方式显得有biger,是install13的必备神器:

    public class Program
    {
        public static void Main()
        {
            var name = String.Format("{0}经典长袖衬衫", "白色");
            var r = String.Format("{0,-10:C}", 126347.89m);
        }
    }

C#6.0中又增加了让人看起来有些晕菜但很巧妙的更高biger的方式:

    public class Program
    {
        public static void Main()
        {
            var color = "白色";
            var name = $"{color}经典长袖衬衫";
        }
    }

这糖,甜过初恋。



using静态类

C#6.0的新东东,可以在代码的顶部这样引用静态类,写法怪异,不乏实用:

using static System.Console;

这糖,甜过初恋。



nameof

C#6.0的新东东,nameof运算符可以作用于变量、函数、类以及名字空间中,用于返回返回其名称,例如:

    public class Program
    {
        public static void Main()
        {
            Console.WriteLine(nameof(Main));  //输出 "Main"

        }
    }

这糖,甜过初恋。



成员索引

C#6.0的新东东,但美貌与智慧为化身的作者君真心没看出有什么用途,或许以后用的到:

    public class Product
    {
        public Product()
        {
            Console.WriteLine(this["白色"]);        //这里输出 白色经典长袖衬衫
        }
        public string this[string color]
        {
            get { return String.Format("{0}经典长袖衬衫", color); }
        }
    }

这糖,甜过初恋。



await

C#5.0引入的await运算符可以非常方便的执行异步运算,但在catch和finally中不能使用,C#6.0放开了这个限制,方便程度那是杠杠的。

这糖,甜过初恋。



无参数的结构体构造函数

C#6.0的新东东,通过new得到的结构体会被调用构造函数,而通过default得到的不会调用:

    public class Product
    {
        public Product()
        {
            Name = "白色经典长袖衬衫";
        }
        public string Name { get; set; }
    }

    public class Program
    {
        public static void Main()
        {
            var p1 = new Product();
            Console.WriteLine(p1.Name); //输出 白色经典长袖衬衫

            var p2 = default(Product);
            Console.WriteLine(p1.Name); //输出空值
        }
    }

这糖,甜过初恋。



亲,就这样收尾了?嗯,是的!

零零散散的搞了这么一大篇,涉及的技术却沧海一粟九牛一毛。那么,咱们约好待到山花烂漫时,你在丛中笑,我再继续搞。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-10 07:56:06

C#语法糖,甜过初恋的相关文章

python_装饰器_语法糖

什么是高阶函数? -- 把函数名当做参数传给另外一个函数,在另外一个函数中通过参数调用执行 #!/usr/bin/python3 __author__ = 'beimenchuixue' __blog__ = 'http://www.cnblogs.com/2bjiujiu/' def func_x(x): return x * 2 def func_y(y): return y * 3 def func_z(x, y): # 等价于 return func_x(5) + func_y(3) r

Java语法糖初探(三)--变长参数

变长参数概念 在Java5 中提供了变长参数(varargs),也就是在方法定义中可以使用个数不确定的参数,对于同一方法可以使用不同个数的参数调用.形如 function(T -args).但是需要明确的一点是,java方法的变长参数只是语法糖,其本质上还是将变长的实际参数 varargs 包装为一个数组. 看下面的例子: 12345678910111213 public class VariVargs { public static void main(String []args) { tes

C#十种语法糖

语法糖 指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用.通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会.需要声明的是"语法糖"这个词绝非贬义词,它可以给我们带来方便,是一种便捷的写法,编译器会帮我们做转换,而且可以提高开发编码的效率,在性能上也不会带来损失. 一.自动属性 以前:手写私有变量+公有属性现在:声明空属性,编译器自动生成对应私有成员字段. 写法:输入prop ,连续按两次tab键,自动生成属性. 1 /// <s

程序设计语言中的语法糖

语法糖是什么呢?按我现在的理解,如果一门语言没有某个语法,照样可以通过其它更通用的方式来表达某种语义.这种语法的引入,只不过是 让表达语义更方便了.那么这个语法,就叫语法糖. Scheme 中有两个关键字 lambda, let ,我目前的理解是,他们就是语法糖. lambda lambda 用来定义一个匿名函数.有时候,一个函数我们只在一个地方用一次,完全没必要给它定义一个名字,这时候,我们就用 lambda 定义 一个匿名函数. 如果没有 lambda ,那么我们定义函数时,会使用下面这种方

看看C# 6.0中那些语法糖都干了些什么(终结篇)

终于写到终结篇了,整个人像在梦游一样,说完这一篇我得继续写我的js系列啦. 一:带索引的对象初始化器 还是按照江湖老规矩,先扒开看看到底是个什么玩意. 1 static void Main(string[] args) 2 { 3 Dictionary<string, string> dic = new Dictionary<string, string>() 4 { 5 ["Name"] = "ctrip", 6 ["Age&qu

深入理解java虚拟机(十二) Java 语法糖背后的真相

语法糖(Syntactic Sugar),也叫糖衣语法,是英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语.指的是,在计算机语言中添加某种语法,这些语法糖虽然不会对语言的功能产生任何影响,却能使程序员更方便的使用语言开发程序,同时增强程序代码的可读性,避免出错的机会.但是如果只是大量添加和使用语法糖,却不去了解他,容易产生过度依赖,从而无法看清语法糖的糖衣背后,程序代码的真实面目. 总而言之,语法糖可以看做是编译器实现的一些"小把戏",这些"小

java语法糖

语法糖 Java语法糖系列,所以首先讲讲什么是语法糖.语法糖是一种几乎每种语言或多或少都提供过的一些方便程序员开发代码的语法,它只是编译器实现的一些小把戏罢了,编译期间以特定的字节码或者特定的方式对这些语法做一些处理,开发者就可以直接方便地使用了.这些语法糖虽然不会提供实质性的功能改进,但是它们或能提高性能.或能提升语法的严谨性.或能减少编码出错的机会.Java提供给了用户大量的语法糖,比如泛型.自动装箱.自动拆箱.foreach循环.变长参数.内部类.枚举类.断言(assert)等 断言(as

python 装饰器语法糖(@classmethod @staticmethod @property @name.)原理剖析和运用场景

引用:http://blog.csdn.net/slvher/article/details/42497781 这篇文章系统的介绍这几者之间的关系和区别.有兴趣的朋友可以到上面的链接查看原文,这里我把原文拷贝如下(如有侵权,通知马上删除) ==================================================================== 在阅读一些开源Python库的源码时,经常会看到在某个类的成员函数前,有类似于@staticmethod或@classme

究竟什么是语法糖呢

其实语法糖只是一个概念,大家可能很早就在接触语法糖了,只是一直不知道这个就是语法糖 百科原话:语法糖(Syntactic sugar),是由Peter J. Landin(和图灵一样的天才人物,是他最先发现了Lambda演算,由此而创立了函数式编程)创造的一个词语,它意指那些没有给计算机语言添加新功能,而只是对人类来说更“甜蜜”的语法.语法糖往往给程序员提供了更实用的编码方式,有益于更好的编码风格,更易读.不过其并没有给语言添加什么新东西. 这里有两点需要注意的: 1语法糖的目的:是为了让代码更