C# 2.0&3.0新特性总结

C# 2.0与3.0新特性解析
本文介绍了C# 2.0引入的范型、匿名方法和迭代器等特性,以及C# 3.0新增的自动实现属性、隐式类型变量、对象与集合初始化、匿名类型、扩展方法和Lambda表达式等内容。

c#2.0新特性

范型

     
我们知道通用的数据结构可以采用object存储任何数据类型。使用object问题是:

  • 显示的强制转带来的代码复杂性
  • 换装箱拆箱的性能损失(为什么有性能损失?因为涉及动态内存分配和运行时类型检查)。还有一些运行时才会出现的类型转换异常也是我们难以在代码编写的时候能够检查到的,防不胜防。

    范型应时而生,它的思路是什么呢?它接受带有类型参数并存储这个类型而不转换它,类型参数在类名字后的<T>中指定。T相当于一个占位符,直到使用的时候才指定一个实际的类型。确切的说当应用程序首次创建一个构造范型类型的实例时,.net公共语言运行时的实时编译器JIT将在进程中把范型IL和元数据转化为本地代码并把类型参数转化为实际的类型。对于这个泛型类型的后续引用将会使用相同的本机代码。这也就是传说中的范型类型实例化。

看一段代码:

范型的一个有趣话题:约束

 

问题溯源:由于T代表的可能是任何类型,所以我们使用T的方法仅限于Equals GetHasCode ToString,那么我们要使用某些特定数据类型的方法呢?比如实现了IComparable接口的数据类型的CompareTo方法?

1 

一种方法是强制转换到IComparable接口。这种方法的缺点是:1.进行运行时动态类型检查增加了性能上的开销,2.自然地如果key没有实现IComparable接口的异常报告推迟到了运行时


另一种方法就是约束列表,关键词是
where,后面跟的是类或者接口的列表,还有一个可选、特殊的new()约束;其实就是说这个类型必须要有一个公开无参构造函数,这就允许泛型类使用这种构造函数来创建实例。约束是一把双刃剑,一方面它提供了编译时类型检查,增强了性能,但是它也限制了范型类型的能力。
2 

范型方法
范型方法在方法名字后面使用
<>指定一个或者多个类型参数,类型参数可以出现在参数列表,返回类型和方法体内。编译器会使用一种类型推断的机制通过其他参数类推断正确的类型参数。

给出一些范型的例子:

ContractedBlock.gifCode

匿名方法

匿名方法其实就是体现了这样一个原则:如无必要,勿增实体;我们在一个简单的WinForm环境中来说明这个问题:一个按钮单击事件我们可以这样来定义响应代码。

 1None.gif   this.button1.Click += delegate
 2ExpandedBlockStart.gif            {
 3InBlock.gif                this.label1.Text = "King2002";
 4ExpandedBlockEnd.gif            };
 5None.gif            
 6None.gif            this.button1.Click += delegate(object sender, System.EventArgs arg)
 7ExpandedBlockStart.gif            {
 8InBlock.gif                this.label1.Text = "Test";
 9ExpandedBlockEnd.gif            };
10None.gif            this.button1.Click += new System.EventHandler(this.button1_Click);
11None.gif private void button1_Click(object sender, EventArgs e)
12ExpandedBlockStart.gif        {
13InBlock.gif            MessageBox.Show("Hello");
14ExpandedBlockEnd.gif        }
15None.gif
16None.gif
17None.gif

匿名方法使得代码对于委托的实现更加简单,匿名方法还有一个用途就是操作一些私有成员,因为它相当于共享了一部分代码。

这里会有一个疑问:匿名方法和委托类型的隐式转换有什么要求?答案:只要参数列表和委托类型的返回值是兼容的就可以完成转换。

  •  参数列表兼容:无参数或者参数的数量、类型、修饰符严格匹配
  • 无返回类型,所有return语句形管的表达式可以被隐式转换到委托的类型

后面我们会看到更简单使用delegate的例子。

 

迭代器

 一个对象如果是可枚举的,那么我们可以使用foreach语句来遍历其中的元素。实际上是调用了这个对象的GetEnumberator方法,它返回一个enumberator(枚举器)。实现枚举器很难但是我们可以使用迭代器实现!

 1None.gif public class DaysOfTheWeek : System.Collections.IEnumerable
 2ExpandedBlockStart.gif    {
 3ExpandedSubBlockStart.gif        string[] m_Days = "Sun""Mon""Tue""Wed""Thr""Fri""Sat" };
 4InBlock.gif
 5InBlock.gif        public System.Collections.IEnumerator GetEnumerator()
 6ExpandedSubBlockStart.gif        {
 7InBlock.gif            for (int i = 0; i < m_Days.Length; i++)
 8ExpandedSubBlockStart.gif            {
 9InBlock.gif                yield return m_Days[i];
10ExpandedSubBlockEnd.gif            }
11ExpandedSubBlockEnd.gif        }
12ExpandedBlockEnd.gif    }
13None.gif
14None.gif    class TestDaysOfTheWeek
15ExpandedBlockStart.gif    {
16InBlock.gif        static void Main()
17ExpandedSubBlockStart.gif        {
18InBlock.gif            // Create an instance of the collection class
19InBlock.gif            DaysOfTheWeek week = new DaysOfTheWeek();
20InBlock.gif
21InBlock.gif            // Iterate with foreach
22InBlock.gif            foreach (string day in week)
23ExpandedSubBlockStart.gif            {
24InBlock.gif                System.Console.Write(day + " ");
25ExpandedSubBlockEnd.gif            }
26ExpandedSubBlockEnd.gif        }
27ExpandedBlockEnd.gif    }
28None.gif

上面是MSDN上的一个简单的例子,有了直观的印象我们可以深究一点:

迭代器是产生值的有序序列的一个语句块,迭代器不是一种成员,它只是实现函数成员的方式。Yield return语句产生迭代的下一个值 yield break 语句指明迭代已经完成;GetEnumerator返回值只要是枚举器接口或者是可枚举接口(System.Collections.IEnumerable   System.Collections.IEnumerator System.Collections.Generic.IEnumerable<T> System.Collections.Generic.IEnumerator<T> ),迭代器就可以被用做函数体。

 

不完整类型
不完整类型完全是为了更好的进行代码管理。仔细观察我们现在添加一个页面时,它的后代代码就使用了不完整类型:

None.gifpublic partial class _Default : System.Web.UI.Page 

 


c#3.0新特性


自动实现属性
Auto-Implemented Properties

   

 1None.gifpublic class Card
 2None.gif
 3ExpandedBlockStart.gif    {
 4InBlock.gif
 5InBlock.gif        //这样的属性是不是简单多了?
 6InBlock.gif
 7ExpandedSubBlockStart.gif        public int ID getset; }
 8InBlock.gif
 9ExpandedSubBlockStart.gif        public string Password getset; }
10InBlock.gif
11ExpandedBlockEnd.gif    }
12None.gif
13None.gif    class Customer
14None.gif
15ExpandedBlockStart.gif    {
16InBlock.gif
17ExpandedSubBlockStart.gif        public double TotalPurchases getset; }
18InBlock.gif
19ExpandedSubBlockStart.gif        public string Name getprivate set; } // read-only
20InBlock.gif
21ExpandedSubBlockStart.gif        public int CustomerID getprivate set; } // read-only
22InBlock.gif
23ExpandedBlockEnd.gif    }
24None.gif

3 

 

  • 自动属性必须包含get set,如果是只读的就添加private关键字
  • Attributes 不允许使用自动属性,这里还是推荐使用常规的属性书写方式

<ms-help://MS.MSDNQTR.v90.en/dv_csref/html/aa55fa97-ccec-431f-b5e9-5ac789fd32b7.htm>
 


检索表达式

Query Expressions

LINQ毫无疑问是c#3.0最抢眼的东西,关于LINQ的文章已经很多,这里不展开,详细资料请参考:

<ms-help://MS.MSDNQTR.v90.en/dv_csref/html/40638f19-fb46-4d26-a2d9-a383b48f5ed4.htm>

 

ExpandedBlockStart.gifint[] items = new int[] 12345 };
None.gif
None.gif            IEnumerable
<int> ints = from item in items
None.gif
None.gif                                    
where item > 2.5
None.gif
None.gif                                    select item;
None.gif
None.gif            
foreach (var p in ints)
None.gif
ExpandedBlockStart.gif            
{
InBlock.gif
InBlock.gif                Console.WriteLine(p);
InBlock.gif
ExpandedBlockEnd.gif            }
 
None.gif
None.gif

 

隐式类型变量
Implicitly Typed Variables (var)

    内部变量的类型可以使用var而不是确切的类型。var关键字可以指示编译器通过右侧的初始化部分来推断实际的数据类型。

 

                    

None.gif  var num = 5;
None.gif
ExpandedBlockStart.gif            var a 
= new[] 2567 };
None.gif
None.gif            
// anon 被编译成匿名类型 注意下面的Name Age都没有定义
None.gif

ExpandedBlockStart.gif            var anon 
= new { Name = "Terry", Age = 34 };
None.gif
None.gif            var list 
= new List<int>();
None.gif
None.gif            
using (var file = new System.IO.StreamReader(@"D:\http.txt", Encoding.Default))
None.gif
ExpandedBlockStart.gif            
{
InBlock.gif
InBlock.gif                Console.WriteLine(file.ReadLine());
InBlock.gif
InBlock.gif                Console.WriteLine(anon.Name );
InBlock.gif
InBlock.gif                Console.WriteLine(anon.Age );
InBlock.gif
ExpandedBlockEnd.gif            }

None.gif
None.gif

var的使用会有一些约束:<ms-help://MS.MSDNQTR.v90.en/dv_csref/html/b9218fb2-ef5d-4814-8a8e-2bc29b0bbc9b.htm>

 

对象、集合初始化

Object and Collection Initializers


设计完成之后生成了一些类代码,但是这里有一个问题就是属性代码的填写,在FX3.0属性代码的已经简化,

类的初始化也提供了更简单的书写方式;可以看一下下面代码段中c2的初始化,列表对象的初始化按照同样的格式也会大大的简化。

 

 1None.gifpublic class Card
 2None.gif
 3ExpandedBlockStart.gif    {
 4InBlock.gif
 5InBlock.gif        //这样的属性是不是简单多了?
 6InBlock.gif
 7ExpandedSubBlockStart.gif        public int ID getset; }
 8InBlock.gif
 9ExpandedSubBlockStart.gif        public string Password getset; }
10InBlock.gif
11ExpandedBlockEnd.gif    }
12None.gif
13None.gif    class Program
14None.gif
15ExpandedBlockStart.gif    {
16InBlock.gif
17InBlock.gif        static void Main(string[] args)
18InBlock.gif
19ExpandedSubBlockStart.gif        {
20InBlock.gif
21InBlock.gif            //通常我们初始化一个对象是这样做的
22InBlock.gif
23InBlock.gif            Card c = new Card();
24InBlock.gif
25InBlock.gif            c.ID = 2002;
26InBlock.gif
27InBlock.gif            c.Password = "henghenghaxi";
28InBlock.gif
29InBlock.gif
30InBlock.gif
31InBlock.gif            //现在我们可以这样做
32InBlock.gif
33ExpandedSubBlockStart.gif            Card c2 = new Card { ID = 23, Password = "testnum" };
34InBlock.gif
35InBlock.gif
36InBlock.gif
37InBlock.gif            Console.WriteLine(c.ID.ToString() + " - " + c.Password);
38InBlock.gif
39InBlock.gif            
40InBlock.gif
41InBlock.gif            //列表的初始化
42InBlock.gif
43InBlock.gif            List<Card> cards = new List<Card>
44InBlock.gif
45ExpandedSubBlockStart.gif            {
46InBlock.gif
47ExpandedSubBlockStart.gif                new Card{ID=12,Password="12sfdgr"},
48InBlock.gif
49ExpandedSubBlockStart.gif                new Card{ID=13,Password="12sdfwsd"},
50InBlock.gif
51ExpandedSubBlockStart.gif                new Card{ID=14,Password="12jkhjh"},
52InBlock.gif
53ExpandedSubBlockStart.gif                new Card{ID=15,Password="1dfsed2"},
54InBlock.gif
55ExpandedSubBlockStart.gif                new Card{ID=16,Password="1sdfsd2"},
56InBlock.gif
57InBlock.gif
58InBlock.gif
59ExpandedSubBlockEnd.gif            };
60InBlock.gif
61InBlock.gif                         //看下面的例子
62InBlock.gif
63ExpandedSubBlockStart.gif            List<int> digits = new List<int> 0123456789 };
64InBlock.gif
65ExpandedSubBlockStart.gif            List<int> digits2 = new List<int> 0 + 112 % 3, MakeInt() };
66InBlock.gif
67InBlock.gif
68InBlock.gif
69InBlock.gif            Console.WriteLine(cards.Count.ToString());
70InBlock.gif
71InBlock.gif            Console.ReadLine();
72InBlock.gif
73ExpandedSubBlockEnd.gif        }
74InBlock.gif
75InBlock.gif               static int MakeInt()
76InBlock.gif
77ExpandedSubBlockStart.gif        {
78InBlock.gif
79InBlock.gif            return DateTime.Now.Second;
80InBlock.gif
81ExpandedSubBlockEnd.gif        }
82InBlock.gif
83InBlock.gif
84InBlock.gif
85ExpandedBlockEnd.gif    }
86None.gif
87None.gif


匿名类型

Anonymous Types

匿名类型把一系列的只读属性封装在一个对象里面,而并没有指定这个对象的类型编译器会给这个对象类型一个名字,但是这个名字在代码级别是不可用的。

看下面的代码:

// anon 被编译成匿名类型 注意下面的Name Age都没有定义

            var anon = new { Name = "Terry", Age = 34 };

            //anon.Age = 23;

  最后一行如果执行编译器会给出一个错误:         

        Property or indexer 'AnonymousType#1.Age' cannot be assigned to -- it is read only        

这个错误信息可以印证上面的说法。继续扩展上面的代码,一起看:

 

None.gifvar card = from c3 in cards
None.gif
None.gif                       
where c3.ID > 13
None.gif
None.gif                       
//select c3;
None.gif

ExpandedBlockStart.gif                       select 
new {MyID= c3.ID,MyPassword= c3.Password };
None.gif
None.gif            
foreach (var item in card )
None.gif
ExpandedBlockStart.gif            
{
InBlock.gif
InBlock.gif              Console.WriteLine(item.MyID.ToString()
+"---"+item.MyPassword );
InBlock.gif
InBlock.gif                
InBlock.gif
ExpandedBlockEnd.gif            }

None.gif
None.gif

这里的代码是匿名类型的一个典型应用,详细请查阅:

<ms-help://MS.MSDNQTR.v90.en/dv_csref/html/59c9d7a4-3b0e-475e-b620-0ab86c088e9b.htm>

 

扩展方法

Extension Methods

扩展方法是一个静态方法,可以关联在一种类型上,所以这个方法可以在他处调用。这样仿佛给某一个类型添加了方法!而实际上我们并没有改变原有的代码。

详情参阅:ms-help://MS.MSDNQTR.v90.en/dv_csref/html/175ce3ff-9bbf-4e64-8421-faeb81a0bb51.htm

  public static class Test

    {

        public static string RemoveWhiteSpace(this string s)

        {

            return s.Replace(" ", "");

        }

    }

定义了上面的方法之后,我们可以在string类型上使用这个方法下面是在开发环境中的截图:

4 

匿名方法

Anonymous Functions

 

 

 

 1None.gifdelegate void Testdelegate(string s);
 2None.gif
 3None.gif        static void Show(string s)
 4None.gif
 5ExpandedBlockStart.gif        {
 6InBlock.gif
 7InBlock.gif            Console.WriteLine(s);
 8InBlock.gif
 9ExpandedBlockEnd.gif        }
10None.gif
11None.gif //1.1里面我们这样做
12None.gif
13None.gif            Testdelegate t = new Testdelegate(Show);
14None.gif
15None.gif
16None.gif
17None.gif            //2.0
18None.gif
19ExpandedBlockStart.gif            Testdelegate t2 = delegate(string str) { Console.WriteLine(str); };
20None.gif
21None.gif
22None.gif
23None.gif            //3.0
24None.gif
25ExpandedBlockStart.gif            Testdelegate t3 = (X) => { Console.WriteLine(X); };
26None.gif
27None.gif            t("Kingtest1");
28None.gif
29None.gif            t2("20022396");
30None.gif
31None.gif            t3("20022458"); 
32None.gif

3.0里面我们的代码使用了Lambda表达式,详情参阅:

ms-help://MS.MSDNQTR.v90.en/dv_csref/html/57e3ba27-9a82-4067-aca7-5ca446b7bf93.htm

Lambada表达式在C#3.0中的典型应用:

ms-help://MS.MSDNQTR.v90.en/fxref_system.core/html/5a7a3466-7d99-dea6-a9fa-04043f951573.htm
 

                    

None.gif// Split the string into individual words.
None.gif

None.gif            
string[] words = sentence.Split(' ');
None.gif
None.gif
None.gif
None.gif            
// Prepend each word to the beginning of the 
None.gif
None.gif            
// new sentence to reverse the word order.
None.gif

None.gif            
string reversed = words.Aggregate((workingSentence, next) =>
None.gif
None.gif                                                  next 
+ " " + workingSentence);
None.gif
None.gif            
bool b = words.All(w => w.Length > 5);
None.gif
None.gif            
bool b2 = words.Any(w => w.Length > 10);
None.gif
None.gif

一句话体会:

    c#新特性的应用需要我们深入的学习以及在团队范围内的知识共享,这样才不致于让代码显得怪异。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值