zoukankan      html  css  js  c++  java
  • Net学习日记_ASP.Net_MVC_新语法笔记

    01.新语法

    本章中主要讲解.Net框架性语法。开发者可以使用新语法提高编程的效率以及代码的运行效率;其本质都是“语法糖”,由编译器在编译时转成原始语法。

    1 自动属性 Auto-Implemented Properties

    2  隐式类型 var

    3  对象初始化器 与 集合初始化器 { }

    4  匿名类 & 匿名方法

    5  扩展方法

    6  系统内置委托 Func / Action  Predicate (bool (T)) / Comparison (int (T,T))

    7  Lambda表达式

    8  标准查询运算符 Standard query operator

    9  LINQ查询表达式

     

    Mvc框架简介:

    浏览器请求 服务器的 某个控制器类 的 Action方法,方法中可以调用业务层等代码处理业务,并产生数据Model,交给视图引擎,视图引擎会找到对应视图,并将数据 “填充到“视图上对应的位置,最终产生整个页面的Html代码,返回给浏览器。

     

    关于编译器:

    编译器会在编译的时候,按照C#语法检查代码,C#语法规定变量只能调用其声明类型的成员,如果声明是父类,则只能调用对象里的父类成员

    自动属性

    回顾传统属性概念

    属性的目的:封装字段,控制 1.读写权限 及 2.字段的访问规则(如:年龄范围)。

    但平时,主要是用来封装 读写权限。

     

    回顾 语法:缺点,臃肿,代码难看!麻烦!

    int id; //字段
    public int Id //属性
    {
         get { return id; }
         set { id = value; }
    }

    自动属性 语法:只需要定义 无实现的属性语法 即可,不需要定义字段。

    public int Id { get; set; }
    public int Age { get; set; }
    public string Name { get; set; }

    查看源码:

    编译后,也生成了对应的属性语法(get和set方法)

    但同时,帮我们生成了一个私有变量

    总结:

    自动属性主要用在对 字段的 读写权限的封装,帮助减少程序员代码,让代码更好看;但实质上在编译时,还是会自动生成一个对应的字段的。

    所以,从这个意义上说,自动属性就相当于是微软提供的一个“语法糖”了。

    思考:

    用自动属性程序员写的代码少了,机器做的事情就多了,那我们到底要不要使用它?

    如果 是针对 读写权限的封装,就推荐使用,因为它是在编译的时候产生了负担,并不是在运行的时候。(不会影响客户运行程序时的效率!)

    但是编译生成的代码也有一个显而易见的缺点,语法太完整,编译后的程序集会比较大。

    隐式类型var

    回顾,传统变量定义方式:

    int age = 11;//传统方式

     隐式类型:在初始化时,就已经根据 = 右边的 值 确定了 var变量的类型了。

    var age1 =12;
    //age1="123";
    var name = "哈哈哈";
    var dog = new Dog();
    
    age1 = 123;
    name = "刘德华";
    dog.Id = 11;

    编译时,已经 把var 转成了 相应的类型了。

    注意:

    1.声明的同时必须初始化,因为编译时要根据初始化值类型来推断var;

    2.声明后不能修改数据类型,因为初始化时已经确定了var类型了;

    3.只能作为方法局部变量使用。类的成员字段、方法的形参和返回值都不能使用!因为无法编译时确定他们的类型!

    4.初始化表达式不能是匿名函数和null。

    查看源码:var 已经不存在了,都被替换成了 初始化值 的 类型。

    对象/集合初始化器

    List<Dog> InitList()
    {
        List<Dog> list = new List<Dog>();
        for (int i = 0; i < 10; i++)
        {
            Dog d = new Dog();
            d.Id = i;
            d.Name = "Ruiky" + i;
            d.Age = i * 2;
            d.Toy = new DogToy();
            d.Toy.ToyId = i;
            d.Toy.ToyName = "狗狗玩具" + i;
            list.Add(d);
        }
        return list;
    }

    对象集合初始化器语法:

    用法1
            List<Dog> InitList()
            {
                List<Dog> list = new List<Dog>();
                for (int i = 0; i < 10; i++)
                {
                    Dog d = new Dog
                    {
                        Id = i,
                        Name = "Ruiky" + i,
                        Age = i * 2,
                        Toy = new DogToy()//使用属性初始化器
                        {
                            ToyId = i,
                            ToyName = "狗狗玩具" + i
                        }
                    };
                    list.Add(d);
                }
                return list;
            }
            //用法2
            List<Dog> InitList()
            {
                List<Dog> list = new List<Dog>{
                     new Dog(){ Id=1, Name="Ruiky", Age=1, Toy = { ToyId=1, ToyName="小球"}},
                     new Dog(){ Id=1, Name="Ruiky", Age=1, Toy = { ToyId=1, ToyName="小球"}},
                     new Dog(){ Id=1, Name="Ruiky", Age=1, Toy = { ToyId=1, ToyName="小球"}},
                     new Dog(){ Id=1, Name="Ruiky", Age=1, Toy = { ToyId=1, ToyName="小球"}},
                     new Dog(){ Id=1, Name="Ruiky", Age=1, Toy = { ToyId=1, ToyName="小球"}}
                 };
                return list;
            }

    用初始化器,创建数组!

    Dog[] dogs = {
          new Dog(){ Id=1, Name="Ruiky", Age=1, Toy = new DogToy{ ToyId=1, ToyName="小球"}},
          new Dog(){ Id=1, Name="Ruiky", Age=1, Toy = new DogToy{ ToyId=1, ToyName="小球"}},
          new Dog(){ Id=1, Name="Ruiky", Age=1, Toy = new DogToy{ ToyId=1, ToyName="小球"}},
          new Dog(){ Id=1, Name="Ruiky", Age=1, Toy = new DogToy{ ToyId=1, ToyName="小球"}},
          new Dog(){ Id=1, Name="Ruiky", Age=1, Toy = new DogToy{ ToyId=1, ToyName="小球"}}
    };

    查看源码:可以看到,编译器帮我们实例化的集合或者数组,并创建了元素对象,设置给数组或集合。

    匿名类

    回顾:

    匿名类语法:

      a.避免过度的数据累积
      b.为一种情况特别进行的数据封装
      c.避免进行单调重复的编码

    var obj = new
                {
                    Id = 1,
                    Name = "Ruiky",
                    Age = 2
                };

    查看源码:

    1.编译器自动为 这个 【匿名类】 创建了一个无命名空间的类型。

    2.在new 关键字处,创建该匿名类对象

    3.编译器创建的匿名类结构

    注意:

    1. 当出现“相同”的匿名类的时候,编译器只会创建一个匿名类

    2. 编译器如何区分匿名类是否相同?

       根据:

              属性名,属性值(因为这些属性是根据值来确定类型的),

              属性个数,属性的顺序。

    匿名方法

    回顾:普通方法定义方式,因为方法的存在是为了 复用 一段代码,所以一般会给方法取个名字,这个方法的引用就可以通过 "方法名"调用。

    void Test()
            {
                Console.WriteLine("哈哈哈~!");
            }

    匿名方法:但是有的方法,不需要复用,仅仅是使用一次就够了,所以不需要方法名,这种方法就叫做匿名方法。

    匿名方法必须结合 委托 使用。(潜在的意思就是:尽管没有方法名了,但方法的指针还是存放在了某个委托对象中)

    如,现在为线程指定要执行的方法的时候,就可以使用匿名方法了。

    注意:

    1.在编译后,会为每个匿名方法创建一个 私有的静态方法,然后将此静态方法传给 委托对象使用。

    扩展方法

    为什么要有扩展方法?      就是为了在不修改源码的情况下,为某个类 增加新的方法。

    语法:

    定义静态类,并添加public的静态方法,第一个参数 代表 扩展方法的扩展类。

    a)       它必须放在一个非嵌套、非泛型的静态类中(的静态方法);

    b)       它至少有一个参数;

    c)       第一个参数必须附加 this 关键字;

    d)       第一个参数不能有任何其他修饰符(out/ref)

    e)       第一个参数不能是指针类型

    public static class DogExtention
        {
            public static string SayHi(this Dog dogObj)
            {
                return string.Format("哈哈哈哈~~~我叫{0}!", dogObj.Name);
            }
    }
    //-----------------------
    //使用扩展方法
    Dog d = new Dog() { 
    Id = 1, Name = "0094", Age = 11, 
    Toy = new DogToy() { ToyId=1, ToyName="小骨头" } 
    };
    string str = d.SayHi();//调用扩展方法,此时的对象d就作为第一个参数传到了扩展方法中
    编译后: string str = DogExtention.SayHi(d);

    注意:

    1.当我们把扩展方法定义到其它程序集中时,一定要注意调用 扩展方法的环境中包含 扩展方法所在的命名空间。如,在Extention下为String类添加一个扩展方法

    然后在页面中使用时,要记得导入命名空间,否则调用不到扩展方法:

    2.扩展方法需要使用特性ExtensionAttribute,当前程序中必须包含程序集ComplilerServices,否则报错如下:

    注:此程序集默认在FrameWork3.5开始自动包含。

    3.因为扩展方法的本质是被编译后替换成静态方法,所以 对象本身 可以为 null,但是在这个扩展方法中,如果访问了第一个参数,则会报“空指针异常”。

    查看源码:

    1.通过源码看到,在执行 string str = d.SayHi();的地方,编译后变成了 这个扩展方法通过静态类的调用方式代码。由此可见,扩展方法并没有被"扩展"到Dog类中,只不过是在编译的时候替换成了静态类里的静态方法而已。d.SayHi()就是一个语法糖!

    思考:如果 Dog类中本身就包含 SayHi方法,那会怎么样?

    但同时包含同名的 实例方法 和 扩展方法时,优先调用实例方法。

    泛型委托

     回顾通过【比较接口】方式:

    让 Dog集合 根据Dog的id排序,需要写一个IComparer<Dog>接口的实现类,在类中重写 接口的 Compare方法,来返回 正整数/0/负整数。

    接口:

    实现类(比较器):

    然后将实现类对象传入集合的Sort方法:

    使用泛型委托 + 匿名方法实现:

    List<T>集合类中包含 新的排序方法,根据 泛型委托Comparison<T> 完成比较过程。

    public void Sort(Comparison<T> comparison);

    看看这个Comparison<T> 泛型委托:

    public delegate int Comparison<in T>(T x, T y);

    修改调用的方法:

    常用系统泛型委托:

    1.System.Func 代表有返回类型的委托
    public delegate TResult  Func<out TResult>(); 
    public delegate TResult  Func<in T, out TResult>(T arg); 
    ......
    注:输入泛型参数-in 最多16个,输出泛型参数 -out 只有一个。
    2.System.Action 代表无返回类型的委托 //list.ForEach
    public delegate void Action<in T>(T obj);    
    public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2); 
    ......
    注:参数最多16个
    3.System.Predicate<T> 代表返回bool类型的委托   //list.Find
    public delegate bool Predicate<in T>(T obj);  
    4.System.Comparison<T> 代表返回int类型的委托  - 用作比较两个参数的大小
    public delegate int Comparison<in T>(T x, T y); //list.Sort

    关于泛型委托的泛型参数列表 in out

    //泛型委托 的 in 泛型参数 代表 可以被作为 参数列表的类型
    //           out 泛型参数 代表 可以被作为 返回值的类型
    public delegate T2 DgSay<in T,out T2>(T t1);

    Lambda表达式

    回顾,发现上面的代码,需要传一个 匿名方法 ,写起来特别别扭。

    能否有简化的语法呢?有!Lambda表达式。

    概念:

    Lambda表达式有两种:

    语法:

    List<Dog> list = InitList();
    //list.FindAll(delegate(Dog d) { return d.Id > 2; });
    //1.表达式 Lambda
    list.FindAll(d => d.Id > 2);// goes to
    list.ForEach(d => Response.Write(d.ToString() + "<br/>"));
    
    //2.语句 Lambda
    list.ForEach(d => { if (d.Id > 2) Response.Write(d.ToString() + "<br/>"); });

    语法进化史:

    查看源码:

    C#语法:list.FindAll(d => d.Id > 2);

    编译成中间代码后,代码太多,简而言之如下:

    编译器帮我们 :

    1.声明一个 Predicate<Dog>委托变量;

    2.创建一个私有的符合委托签名的静态方法;

    3.实例化委托变量,并将方法 传入;

    4.调用list.FindAll方法,并传入委托变量。

  • 相关阅读:
    【Qt开发】 V4L2_CAP_VIDEO_OVERLAY与V4L2_CAP_VIDEO_CAPTURE的区别
    【Qt开发】QThread 实用技巧、误区----但文档中没有提到
    【Qt开发】QThread 实用技巧、误区----但文档中没有提到
    【Qt开发】事件循环与线程 二
    【Qt开发】事件循环与线程 二
    【Qt开发】事件循环与线程 一
    【Qt开发】事件循环与线程 一
    【Qt开发】QThread介绍
    【Qt开发】QThread介绍
    【Linux开发】如何查看Linux kernel的内置模块驱动列表和进程ID
  • 原文地址:https://www.cnblogs.com/lisong-home/p/8207086.html
Copyright © 2011-2022 走看看