`

C#3.0新特性

    博客分类:
  • C#
阅读更多

C#3.0 的新特性主要有:

a、 隐含类型局部变量

b、 扩展方法

        c、   对象与集合初始化器

d、 匿名类型

        e、  Lambda 表达式

f、  查询表达式(LINQ

g、 表达式树

 

隐含类型局部变量:

var str= 5;

1 var 为关键字,可以根据后面的初始化语句自动推断类型,需要注意的是右边的不能为null

2 、初始化语句必须为表达式(不能是对象也不能是一个集合的初始化器),且编译时可以推断类型;

3 Var 声明仅限于局部变量,亦可以用在foreachusing 等语句中;

4 、数组也可以作为隐含类型,但是如果在里面混合了,则会出错。var a = new[]{1,2,3,4,5}; 但是var a = new[]{1,"hello",3,4,5}; 出错。编译器不会转换为Obejct 类型;

5 、注意这里var 不是一个类型,可以把它看作是一个占位符,编译器可以把它替换成一个具体的类型(强类型),可以把与Object 相比较,但是效率要比Object 高;

 

扩展方法:

           public static class Extensions

        {

            public static void Foo(this string s){

                      ......

               }

        }

 

String s = "Hello World";

s.Foo();//会转换成Extensions.Foo(s);

扩展方法允许我们子不改变源代码的情况下扩展(即添加)现有类型中的实例方法(继承、包含、反射、扩展方法);

   class Program

    {

        static void Main(string [] args)

        {

            // 调用扩展方法

            Console .WriteLine("1" .In(new [] { "1" , "2" , "3" }));

            Console .ReadKey();

        }

    }

    public static class helper

    {

        public static bool In(this object o, IEnumerable b)

        {

            foreach (object obj in b)

            {

                if (obj == o)

                    return true ;

            }

            return false ;

        }

    }

 

       扩展方法的本质是将实例方法调用在编译期改变为静态类中的静态方法调用

       扩展方法的优先级:现有实例方法优先级最高,其次为最近的namespace 下的静态类的静态方法,最后为较远的namespace 下的静态类的静态方法。

扩展方法是一种编译时技术,注意与反射等运行时技术进行区别,并慎重使用。

说明:

1 、扩展方法是给现有类型添加一个方法;

2 、扩展方法是通过 指定关键字this 修饰方法的第一个参数;

3 、扩展方法必须声明在静态类中;

4 、扩展方法要通用对象来调用;

5 、扩展方法可以带参数。

         6 、如果扩展方法名和原有方法名发生冲突,那么扩展方法将失效。

 

对象与集合初始化器:

       先介绍一下自动属性:

       private string m_ID;

    //ID 属性定义,这种写法大家都很熟悉

    public string ID

    {

         get { return m_ID; }

         set { m_ID = value ; }

    }

// C#3.0 中大大简化这种属性的写法

public string ID { get ; set ; }

 

  以前我们习惯编写的方式:

      public Program()

      {

      }

      public Program(string pID)

      {

         ID = pID;

      }

      public Program(string pID,string pName,string pAge)

      {

         ID = pID;

         Name = pName;

         Age = pAge;

      }

      public string ID{ get ; set ;}

      public string Name{get ;set ;}       

      public string age{get ;set ;}

      //Customer 对象初始化

      Program program = new Program();

      program.ID = "001" ;

      program.Name = "Test001" ;

      program.Age = "28" ;

      

      // 或者使用构造函数

      Program program = new Program("001" ,"test001" ,"28" );

 

现在我们使用对象初始化器:

public Program()

      {

      }

      public string ID{ get ; set ;}

      public string Name{get ;set ;}       

      public string age{get ;set ;}

      

      // 对象初始化 ( 想要初始化几个属性都可以 )

      Program program = new Program(ID="001" ,Name="test001" ,age="28" );

 

从本质上来说只是简化了代码编写的工作,后台编译器自动完成转换。对象初始化器实际上利用了编译器对对象中对外可见的字段和属性进行按序赋值,在编译时还是隐式调用了构造函数,对字段或属性的进行逐一赋值。

除了在初始化类时设置简单的属性值外,对象初始化器特性也允许我们设置更复杂的嵌套(nested) 属性类型:

Program program = new Program { ID="001" ,Name="test001" ,age="28" ,

        Detail=new ProgramDetail{Address="anhui" ,DeliAddress="hefei" }};

 

集合初始化器:

       集合初始化器会对初始化器中的元素进行按序调用ICollection<T>.Add(T) 。应用集合初始化器的对象的类型必须实现了System.Collections.Generic.ICollections<T> 接口并指定了确定的T

    List <int > num = new List <int > { 0, 1, 2, 6, 7, 8, 9 };

    List <Program > programs = new List <Program >{

        new Program {ID="001" ,Name="test001" ,age="28" },

        new Program {ID="002" ,Name="test002" ,age="29" },

        new Program {ID="003" ,Name="test003" ,age="30" } };

 

注意对象初始化器和集合初始化器中成员的可见性和调用顺序。对象与集合初始化器同样是一种编译时技术。

 

匿名类型:

       匿名类型是使用new 关键字调用对象初始化器创建的一个匿名类型的对象,匿名类型直接继承自System.Object 。匿名类型的成员是编译器根据初始化器推断而来的。

var obj = new { a = "this is only a test" , b = 10, c = (decimal )20 };

Console .WriteLine(" 匿名对象值 : \n A={0},\n B={1},\n C={2}" , obj.a, obj.b, obj.c);

Console .ReadKey();

 

 

Lamdba 表达式:

Lamdba 表达式可以取代delegate ,作为方法指针来使用。首先先描述一下Lamdba 表达式格式:

(参数列表)=> 表达式或者语句块

可以有多个参数,一个参数,或者无参数。参数类型可以隐式或者显示。例如:

1 (x,y)=>x*y// 多个参数,隐式类型=> 表达式

2 x=>x*10// 单个参数,隐式类型=> 表达式

3 x=>{return x*10;}// 单个参数,隐式类型=> 语句块

4 (int x)=>x*10// 单参数,显示类型=> 表达式

5 (int x)=>{return x*10;}// 单参数,显示类型=> 语句块

6 ()=>Console.WriteLine()// 无参数

格式要点:

1 Lamdba 表达式的参数类型可以忽略,因为可以根据使用的上下文进行推断。

2 Lamdba 表达式的主体(body) 可以是表达式,也可以是语句块。

3 Lamdba 表达式传入的实参将参与类型推断,以及方法重载辨析。

4 Lamdba 表达式表达式和表达式体可以被转换为表达树。

Lambda 表达式与委托类型:

Lamdba 表达式L 可以被转换为委托类型D ,需要满足以下条件:

       L D 拥有相同的参数个数,对应的顺序。

       L 的参数类型要与D 的参数类型相同。注意隐式类型要参与类型辨析。

       D 的返回类型与L 相同,无论L 是表达式,还是语句块。

       Lambda 表达式并不是表达式,而是一种委托类型的对象。任何匿名方法的应用,都可以写作Lambda 表达式

Demo:

  class Program

    {

        static void Main()

        {

            List <Person > persons = new List <Person >

                  {

                     new Person {Name = " 张三 " ,Sex = " D" ,Age = 22},

                      new Person {Name = " 李四 " ,Sex = " " , Age = 23},

                     new Person {Name =" 王五 " ,Sex = " " , Age =25},

                      new Person () { Name = " 丽丽 " ,Sex = " " ,Age = 34}

                   };

            Console .WriteLine(" Lamdba 表达式查找,张三 " );

            Person person = persons.Find(a => (a.Name == " 张三 " ));

            Console .WriteLine(string .Format("{0},{1}" , person.Name, person.Age));

 

Console .WriteLine(" 通过委托查找张三 " );

//Perdicate 表示泛型委托

            Predicate <Person > per = new Predicate <Person >(isZhangSan);

            Person perW = persons.Find(per);

             Console .WriteLine(string .Format("{0},{1}" , perW.Name,perW.Age));

 

 

            Console .WriteLine(" 通过匿名方法查找张三 " );

            Person perN = persons.Find(delegate (Person perso) { return perso.Name== " 张三 " ; });

             Console .WriteLine(string .Format("{0},{1}" , perN.Name, perN.Age));

 

 

            Console .WriteLine(" Lamdba 表达式查找,所有性别为男的人 " );

            List <Person > personList = persons.FindAll(a => (a.Sex == " " ));

            foreach (Person person in personList)

            {

Console .WriteLine(string .Format(" 姓名 :{0}\t 年龄 :{1}\t " , person.Name, person.Age));

            }

            Console .ReadKey();

        }

          private static bool isZhangSan(Person person)

        {

            return person.Name == " ? ¨y" ;

        }

    }

    class Person

    {

        public string Name { get ; set ; }

        public string Sex { get ; set ; }

        public int Age { get ; set ; }

    }

 

通过这里Demo ,通过反编译可以看到不管是匿名方法,还是Lamdba 表达式,编译器实际上为我们做了“生成相关代理”的动作,或者说其实际的执行还是通过代理实现的,而整个演变过程都是为了开发者开发方便而进行的“代码”改进;

 

查询表达式(LINQ ):

          static void Main(string [] args)

        {

            string [] names = { "aaa" , "bbb" , "ccc" , "dddd" , "eeee" , "fff" , "gggg" };

            IEnumerable <string > query =

from s in names

where s.Length == 3

orderby s

select s.ToUpper();

            // 方法风格(基于方法)的查询,注意方法里的参数为 Lamdba 表达式

            IEnumerable <string > query1 = names

.Where(s => s.Length == 3)

.OrderBy(s => s)

.Select(s => s.ToUpper());

            // 委托

            Func <string , bool > filter = delegate (string s) { return s.Length == 3; };

            Func <string , string > extract = delegate (string s) { return s; };

            // 第一个参数表示此委托封装方法的参数类型

            Func <string , string > project = delegate (string s) { return s.ToUpper(); };

            IEnumerable <string > query = names.Where(filter)

                                                 .OrderBy(extract)

                                                  .Select(project);

            foreach (string item in query)

            {

                Console .WriteLine(item);

            }

            Console .ReadKey();

        }

 

通过上面的代码方法发现LINQ 表达式它的判断就是委托,操作符就是方法,其方法定义在namespace System.Linq 空间下。其思想就是用一种类似于我们关系型数据库的操作方式允许我们去针对一些和我们OO.net 不符合的领域,比如像数据库领域,xml 领域等去表达我们的操作,而不是去使用对象式的。现在使用的是关系型的。

 

LINQ to SQL:

       LINQ to SQL 是作为ADO.NET 的一个重要组件,而非完全替代品。

具体在以后的专题中进行详细的描述;

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics