[C#详解] (1) 自动属性、初始化器、扩展方法
文章来源:Slark.NET-博客园 http://www.cnblogs.com/slark/p/CSharp-focus-1.html
代码下载:点我下载
目录
前言
首先祝大家2015新年快乐!
新的一年,新的开始。来博客园安家已经快两个月了。每天看博客、写博客、评论、回答博问已经渐渐养成了一种习惯。可以很明显的感觉到泡在博客园里真的可以学到很多,不论是技术文章的还是一些记叙经历、抒发感想的随笔,都让我从各个方面受益良多。不知道大家是否和我一样,就是感觉博客园有一种特殊的魔力,让你没事就想上去看一眼,看上面是不是又有人发了新文章,而且累了的时候在上面看看非技术的东西也能放松自己。
有时会问自己:在博客园上花了这些时间和精力,是否值得?毕竟这也算是"义务劳动",不为自己创造任何价值,通俗点说就是不挣钱。但是每想一次这个问题我都会更加坚定自己的选择。坚持博客园的理由有三:
- 不断地利用博客园中的技术知识提高自己的技术水平,这无疑是在增加自身的价值。我觉得要想拿高工资,最本质的问题就是提高自身价值。对于我们技术人员来讲,就是知识面越广、掌握的技术越深入、编码的速度越快、质量越高、解决难题的问题越强,我们的价值就越高。博客园在这些方面对我们都是有帮助的。
- 博客园中的非技术博客和新闻,让我们可以了解到同行业的人的工作、生活以及感情状态。并能针对程序员提供对口的业界新闻。这样可以让我对自己、以及同行业的人、包括整个行业有了更加清楚的认识。它让我对自己在行业中所处的地位有一个更加清晰的认识,这样一来可以更加准确的把握自己,更好的规划自己的职业生涯。
- 博客园是一个展示的舞台。我看到很多博客里有发自己公司的招聘广告,或者推销自己的产品、自己的网站。没错,他们用这个优质的程序员聚集的平台,为自己打广告,而且还是免费的。这何乐而不为呢。对于目前的我来说,暂时还不需要广告什么,但是通过博客让更多的人认识我,了解到我的技术水平,肯定有百利而无一害的。免费给自己做广告,怎么看都是赚的。
因此,坚持博客园绝对是一个现实的决定。我相信我能一直做下去。
回到我们的博客本身。之前写了10篇MVC5 + EF6 + Bootstrap3系列教程,今年会继续写下去。毕竟这三项技术都是我大大看好的。在写这个系列的时候,有些遗憾的是,很多C#本身的技术点与MVC关系不大。详细写的话怕跑题,不写怕读者看不懂,一直都有点尴尬。因此我新开了这个专题[C#详解]来把那些曾经要讲而没有讲的东西一一讲讲清楚。这样自己也安心了。因此看了[C#详解]系列会使你在看MVC5 + EF6 + Bootstrap3系列时更加清楚明白。而看[C#详解]时也可以去MVC5 + EF6 + Bootstrap3找到这些知识点的实际应用场景。这样相辅相成,效果应该很好。
属性与自动属性
在解释自动属性之前有必要先说说属性。
属性
我们知道要符合面向对象编程的原则,一个类里面的变量最好是私有的。如下所示:
class Student { private int _id; }
这样保证了类的封装性。可是把它封装起来总得有办法从外部访问它,要不然就没有存在的必要了。因此这里我们就用到了属性。代码如下所示:
1 class Student 2 { 3 private int _id; 4 public int Id 5 { 6 get 7 { 8 return _id; 9 } 10 set 11 { 12 _id = value; 13 } 14 } 15 }
上面代码中第4行定义了一个名为Id的属性,通过它就能访问到私有变量_id。Id属性内部有get和set两个访问器,get访问器用于获取私有变量的值,set访问器用于给私有变量赋值。下面的代码展示如何使用属性:
1 Student student = new Student(); 2 student.Id = 3; 3 Console.Write(student.Id);
第2行调用set访问器给Id赋值,第3行,调用get访问器获取Id值显示出来,结果如下:
属性的功能不仅如此,我们可以给get访问器加入代码来对输出做处理或者给set加入代码来对赋值做处理。示例如下:
1 class Student 2 { 3 private int _id; 4 public int Id 5 { 6 get 7 { 8 return _id + 100; 9 } 10 set 11 { 12 if (value > 0) 13 { 14 _id = value; 15 } 16 else 17 { 18 _id = 0; 19 } 20 } 21 } 22 }
第8行的代码使Id属性在输出时加100,第12-19行,使Id属性在赋值时若值小于0,则赋值为0。
用下面代码调用上面的类。
1 Student student = new Student(); 2 student.Id = -3; 3 Console.Write(student.Id);
第二行执行后Id属性会赋值为0,然后在输出时会变为100。
自动属性
属性的定义是繁琐的,这里我们就可以用自动属性来简化代码。同样是定义一个对输入输出不做任何特殊处理的属性,我们可以这样写:
1 class Student 2 { 3 public int Id { get; set; } 4 }
第3行就是我们的自动属性了,其写法就是在属性后加{ get; set; }。省了私有变量和访问器的定义,一行就搞定,但其功能还是和以前的属性一模一样。这就是自动属性的好处。但是自动属性不能实现前面提到过的对输入输出做特殊处理。
另外,想要把一个属性变为只读的,用自动属性可以这样写:
1 class Student 2 { 3 public Student(int id) 4 { 5 Id = id; 6 } 7 public int Id { get; private set; } 8 }
上面代码中第7行在set访问器前面加上private,属性赋值没办法被外部调用,自然是变成只读属性了。但在第3-6行要记得加入构造函数给属性赋初值。这个类的调用方法如下:
1 Student student = new Student(3); 2 Console.Write(student.Id);
第1行用构造函数给Id赋值,第2行获取所赋的值。结果如下:
初始化器
初始化器分为对象初始化器和集合初始化器。下面一一介绍。
对象初始化器
对象初始化器的作用,简单点说就是可以使我们初始化一个类的代码变得更简洁。比如下面这个类:
class Person { public string Name { get; set; } public int Age { get; set; } public string Address { get; set; } }
我们要初始化它并对它赋值的话通常要这样:
Person person = new Person(); person.Name = "Slark"; person.Age = 100; person.Address = "Xi'an";
这里我们用了一行创建对象语句,加三行赋值语句。这里光person这个变量就出现了4遍,繁琐。用对象初始化器来代替这些操作:
Person person = new Person { Name = "Slark", Age = 100, Address = "Xi'an" };
同样的效果,对象初始化器只用了一行,简洁!可以看到对象初始化器将创建对象和赋值合为一行,其中赋值就是在后面大括号里做的。这里的赋值可以给所有属性赋值,也可以给部分属性赋值。
集合初始化器
既然要讲集合初始化器,那么我们就先来创建一个集合:
List<int> intList = new List<int>(); intList.Add(1); intList.Add(2); intList.Add(3);
好,这里我们用4行代码创建了一个3个元素的集合。集合初始化器的出现大大减少了我们对这种操作的代码量。其对应的集合初始化器代码为:
List<int> intList = new List<int> { 1, 2, 3 };
嗯,真的少写了很多。集合初始化器的原理也很简单,就是它默默的为我们调用了List的Add方法依次为我们添加了这3个元素。
这里我们再给一个综合运用集合初始化器和对象初始化器的例子:
List<Person> personList = new List<Person> { new Person { Name = "Slark1", Age = 101, Address = "Xi'an1" }, new Person { Name = "Slark2", Age = 102, Address = "Xi'an2" }, new Person { Name = "Slark3", Age = 103, Address = "Xi'an3" } };
代码里用集合初始化器初始化了personList,然后用对象初始化器初始化了3个Person对象实例。这其中省了多少代码,真是不谈了。
扩展方法
扩展方法,简单点说就是可以在不改变现有类的情况下给这个类添加方法。我觉得扩展方法的最大意义在于我们可以给那些我们根本无法修改的类,比如String,添加我们自定义的方法。既然无法通过修改来添加,那就只能通过扩展了。
这让我想到了开闭原则(Open-Close Principle,OCP):一个软件实体应该对扩展开放,对修改关闭。
既然类对扩展开放了,我们就赶紧来试试吧!
无参数扩展方法
先试着给String添加一个DoubleString方法,就是把这个字符串输出两遍。
先创建一个静态类StringExtension:
1 static class StringExtension 2 { 3 public static string DoubleString(this string str) 4 { 5 return str + str; 6 }
7 }
注意第1行,我们把要扩展的方法放在一个类里,并且这个类必须是静态类,要加static。类的名字随便起,无所谓。第3-6行就是我们想要扩展的方法。这个方法比较特殊,在定义的时候要写成静态方法,但是在调用的时候要当实例方法用。这个方法的参数写成this string str 表示要把这个方法加到String类中。但是这个方法在调用时是不能加参数的。
调用方法如下:
string str = "ABCD"; Console.Write(str.DoubleString());
可以看到,扩展的方法DoubleString被调用的时候被当作实例方法,并且没有参数。运行结果如下:
结果符合我们的预期。
带参数扩展方法
如果要给扩展方法带参数怎么办?示例代码如下:
1 static class StringExtension 2 { 3 public static string RepeatString(this string str, int row,int column) 4 { 5 string s = string.Empty; 6 for (int i = 0; i < row; i++) { 7 for (int j = 0; j < column; j++) 8 { 9 s += str + " "; 10 } 11 s += "\r\n"; 12 } 13 return s; 14 } 15 }
注意第3行这里一共有3个参数,其中后两个参数会在调用这个扩展函数的时候被赋值,这里这个RepeatString函数会把一个字符串写成几行几列的矩阵。
调用方法如下:
string str = "ABCD"; Console.Write(str.RepeatString(3,4));
调用时的第一个参数对应定义时的第二个参数,调用时的第二个参数对应定义时的第三个参数。显示结果如下。
结尾
呼呼~ 终于写完了,腰酸背痛腿抽筋。
喜欢就推荐下吧!
作者:Slark.NET
出处:http://www.cnblogs.com/slark/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。如有问题或建议,请多多赐教,非常感谢。