zoukankan      html  css  js  c++  java
  • C#学习笔记(二)

    表达式

    编程语言的表达式:用于求值的表达实体,最小的算法元素

    C#对表达式的定义: (一个或多个操作数)和(0个或多个操作符组成)

    获取类型名称:xxx.GetType().FullName

    语句

    定义:最小的独立元素,表达式可以组成语句,语句是高级语言才有的,低级语言只有指令。

    高级语言中的表达式对应低级语言中的指令,语句等价于一个或一组有明显逻辑关联的指令。

    编程:使用语句编写程序

    变量的作用域:

    字段

    什么是字段:

    • 一种表示与对象或类型(类或结构体)关联的变量
    • 字段是类型的成员(声明在方法里的是局部变量,不叫字段),旧称成员变量
    • 与对象关联的字段也称为“实例字段”
    • 与类型关联的字段称为静态字段,由static修饰

    字段的声明:

    • 一定是名词

    字段修饰符:

    • new
    • public:(可以修饰类也可以修饰成员)公共的,最高的访问级别,访问没有限制,命名大写字母开头
    • protected:(只修饰成员)受保护的, 只有在当前类内部及所有的子类内部可以访问。基类中访问无限制,子类中直接访问或通过子类实例访问。
    • private:(只修饰成员)私有的,最低的访问级别,被private访问修饰符修饰的成员只有在当前类的内部可以访问,其他地方一律不得访问,命名小写字母开头
    • static
    • readonly
      • 实例只读字段:只能在创建实例的时候可以初始化
      • 静态只读字段:静态构造器中初始化
    • volatile

    this代表当前实例

    字段的初始值:

    • 无显示初始化时,字段获得其类型的默认值,所以字段“永远都不会被初始化”
    • 静态字段初始化时期:类型被加载(load)时,静态构造器,加载这个类型的时候
      // 静态构造器
      Class Brush
      {
          public static readonly int a;
          static Brush()
          {
                 Brush.a = 10;
          }
      }
    • 实例字段初始化时机:对象创建时

    属性

    什么是属性

    • 属性(property)是一种用于访问对象或类型特征的成员,为C#所特有
    • 属性是字段的自然扩展
      • 从命名上看,field更偏向于实例对象在内存中的布局, property更偏向于反应现实世界对象的特征 
        public int Age
        {
            get
            {
                return this.age;
            }
            set   // value是set中才有的关键字,代表用户传进来的值,可以在set中进行值检验
            {
                this.age = value;
            }
        }
        // 使用
        class.Age
      • 对外:暴露数据,数据是可以存储在字段里的,也可以是动态计算出来的
      • 对内:保护字段不被非法值污染
    • 属性由Get/Set方法对进化而来
    • 语法糖

    属性的声明

    • 完整声明:propfull 加两下tab(也可以通过vs的refactor工具)
      class Student
      {
              private int myVar;   // 被属性包装的字段的名字
      
              public int MyProperty
              {
                  get { return myVar; }
                  set { myVar = value; }   // 可以在这里加代码以保护逻辑
              }
      }
    • 简略声明:通过简略声明声明出来的属性,功能上和一个公有的字段是完全相同的,好处在于声明起来比较简单,带有这种属性的类就是为了传递数据用的

      // prop 两下tab
      public int MyProperty {get; set;}

    属性和字段的关系

    • 一般情况下,它们都用于表示实体(对象或类型)的状态
    • 属性大多情况下是字段的包装器(wrapper)
    • 建议:永远使用属性(而不是字段)来暴露数据,即字段永远是private或protected

    索引器

    索引器(indexer)是这样一种成员:它使对象能够用与数组相同的方式(即使用下标)进行索引,一般用在集合里面

    索引器的声明

    indexer 两下tab

    常量

     const 修饰,隶属于类型而不是对象,没有实例常量,”实例常量“的角色由只读实例字段来担当。可以提高程序的可读性和执行效率。

    参数

    传值参数:声明时不带修饰符的形参是值形参

    后续。。。。

    委托

    什么是委托

    • 委托(delegate):是函数指针的升级版,java中没有与委托相对应的功能实体
      • 实例:C/C++中的函数指针
        // 定义一个名为Calc函数指针,它指向了有两个参数,且返回整型的函数,并把它定义为一种数据类型
        typedef int(*Calc)(int a, int b); 
        // 使用, Add,Sub是已定义好的函数 
        Calc func1 = &Add; 
        Calc func2 = ⋐
        z = func1(1, 2);
    • 一切皆地址
      • 变量(数据)是以某个地址为起点的一段内存中所储存的值
      • 函数(算法)是以某个地址为起点的一段内存中所存储的一组机器语言指令
    • 直接调用与间接调用
      • 直接调用:通过函数名来调用函数,CPU通过函数名直接获得函数所在地址并开始执行,返回
      • 间接调用:通过函数指针来调用函数,CPU通过读取函数指针存储的值获得函数所在地址并开始执行,返回
    • 委托的简单使用
      • Action委托:用于没有返回值的方法
        // 声明
        Action action = new Action(目标方法名);
        // 使用1
        action.Invoke();
        // 使用2
        action();
      • Func委托: 用于有返回值的方法
        // 声明,可以没有参数
        func<参数1类型,参数2类型, 返回值类型> 委托名= new Func<参数1类型,参数2类型,返回值类型>(方法名);
        // 使用1
        委托名.Invoke(x, y);
        // 使用2
        委托名(x, y);

    委托的声明(自定义委托)

    • 委托是一种类(class),类是数据类型,所以委托也是一种数据类型
    • 它的声明方式与一般类不同,主要是为了照顾可读性和C/C++传统
      // 自定义委托
      public delegate 返回值类型 委托类名(参数1类型 参数1名称, 参数2类型,参数2名称);
      // 自定义委托声明
      委托类名  委托实例名 = new 委托类名(目标方法名);
      // 自定义委托使用1
      委托实例名.Invoke(参数1,参数2);
      // 自定义委托使用2
      委托实例名();
    • 注意声明委托的位置
      • 应该声明在名称空间体内,与其他的类处在同一级别
    • 自定义的委托与所封装的方法必须”类型兼容“
      • 返回值的类型抑制
      • 参数列表在个数和数据类型上一致

    委托的一般使用

    • 实例:把委托当做方法的参数传给另一个方法,形成一种动态调用方法的结构
      • 正确使用1:模板方法,”借用“指定的外部方法来产生结果:符合面向对象的开闭原则,即软件修改的时候,应该尽量用扩展进行变化,而不是通过修改已有的代码。
        • 使代码复用reuse,通过委托来调用相关的方法,如果扩展的话,只需要写在委托中就行了,不需要修改原来的类(python装饰器功能类似)
        • 把方法当做参数传递,达到动态调用的方式
      • 正确使用2:回调(callback)方法,调用指定的外部方法
      • 无论是模板方法还是回调方法,都是用委托类型的参数,封装一个外部方法,把这个方法传进方法的内部,再进行间接调用
    • 注意:难精通 + 易使用 + 功能强大,一旦被 滥用后果很严重
      • 缺点1:这是一种方法级别的紧耦合,现实工作中要慎用
      • 缺点2:可读性下降,debug难度增加
      • 缺点3:把委托回调,异步调用和多线程纠缠在一起,会让代码变得难以阅读和维护
      • 缺点4:委托使用不当有可能造成内存泄漏和程序性能下降

    委托的高级使用

    • 单播委托:一个委托封装一个方法的使用形式。
    • 多播(multicast)委托:一个委托内部封装了不止一个方法,也是同步调用。action1 += action2
    • 隐式异步调用
      • 同步与异步简介
        • 中英文有语言差异
        • 同步:A先做完B再接着A做
        • 异步:A和B同时做,相当于汉语中的同步进行
      • 同步调用和异步调用对比
        • 每一个运行的程序是一个进程(process)
        • 每个进程可以有一个或者多个线程
        • 同步调用是在同一线程内
        • 异步调用的底层机理是多线程
        • 串行 == 同步 == 单线程, 并行 == 异步 == 多线程
      • 隐式多线程 V.S. 显示多线程
        • 直接同步调用:使用方法名
        • 间接同步调用:使用单播/多播委托的Invoke方法
        • 隐式异步调用:使用委托的BegingInvoke,action1.BeginInvoke(Callback, object) BeginInvoke方法会自动的生成一条分支线程,在这个线程中去执行方法。callback参数是执行完后回调的方法,不需要可以为null,另一个参数一般为null
        • 显示异步调用:使用Thread或Task
    • 应当适时地使用接口(interface)取代一些对委托的使用
      • Java完全地使用接口取代了委托的功能

    事件

    初步了解事件

    • 定义:Event,能够发生的什么事情
    • 角色:使对象或类具备通知能力的成员
    • 使用:用于对象或类间的动作协调与信息传递(消息推送)
    • 原理:时间模型(event model)中的两个5
    • ”发生 >响应“中的5个部分:闹钟响了人起床,闹钟,响,人,起床,暗含了人订阅了闹钟响了的事件,共5个 
    • ”发生 >响应“中的5个动作:
      1. 我有一个事件(事件参数)
      2. 一个或一群人关心(订阅)这个事件(事件的订阅者)
      3. 我的事件发生了
      4. 关心这个事件的人会收到通知
      5. 收到通知的人会对事件进行影响(处理事件)
    • 提示
      • 事件多用于GUI界面开发
      • 各种编程语言对这个机制的实现方法不尽相同
      • java中没有事件这种成员。Java用接口来实现事件
      • MVC, MVP, MVVM等模式是事件模式的更高级,更有效的用法(事件模式牵扯到的元素太多,有5个)
      • 日常开发的时候,使用已有事件的机会比较多,自己声明的机会比较少

    事件的应用

    • 事件模型的五个部分
      1. 事件的拥有者(event source , 对象)
      2. 事件成员(event, 成员, 事件本身,向订阅者发送通知 )
      3. 事件的响应者(event subscriber, 对象或类,拥有自己的事件处理器,订阅了事件的对象或类)
      4. 事件处理器(event handler,方法成员,回调方法),sender:事件的发送者
      5. 事件订阅——把事件处理器与事件关联在一起,本质上是一种以委托类型为基础的“约定”
    •  事件模型五个部分的不同组合
      1. 事件的响应者去向事件的拥有者订阅事件,两个类(MVC模式的雏形)
        using System;
        using System.Timers;
        
        namespace ConsoleApp2
        {
            class Program
            {
                static void Main(string[] args)
                {
                    Timer timer = new Timer(); // 事件的拥有者
                    timer.Interval = 1000;  // 1000ms执行一次
                    Boy boy = new Boy();    // 事件的响应者
                    // 事件: timer.Elapsed       
                    timer.Elapsed += boy.Action;  //事件 订阅(+=)  事件处理器 
                    timer.Start();
                    Console.ReadLine();
                }
            }
        
            class Boy
            {
                // 事件的处理器
                internal void Action(object sender, ElapsedEventArgs e)
                {
                    Console.WriteLine("Jump");
                }
            }
        }
        View Code
        using System;
        using System.Windows.Forms;
        
        namespace netframework
        {
            class Program
            {
                static void Main(string[] args)
                {
                    Form form = new Form();  //  事件拥有者
                    Controler controler = new Controler(form);  // 事件响应者
                    form.ShowDialog();
                }
            }
        
            class Controler
            {
                private Form form;
                public Controler(Form form)
                {
                    if (form != null)
                    {
                        this.form = form;
                        this.form.Click += this.FormClicked;  // 事件  订阅   事件处理器
                    }
                }
                // 事件处理器
                private void FormClicked(object sender, EventArgs e)
                {
                    this.form.Text = DateTime.Now.ToString();
                }
            }
        }
        View Code
      2. 事件的拥有者同时也是事件的响应者 ,拥有者和响应者属于同一个类
        using System;
        using System.Windows.Forms;
        
        namespace netframework
        {
            class Program
            {
                static void Main(string[] args)
                {
                    MyForm form = new MyForm();     // 事件拥有者   事件响应者
                    form.Click += form.FormClicked;//  事件 订阅 事件处理器
                    form.ShowDialog();
                }
        
            }
        
            class MyForm : Form
            {
                internal void FormClicked(object sender, EventArgs e)
                {
                    this.Text = DateTime.Now.ToString();
                }
            }
        }
        View Code
      3. 事件的拥有者是事件的响应者的一个字段成员,事件的响应者用自己的一个方法订阅了自己成员的某个事件,也是windows平台上默认的事件订阅处理结构,意义最大
        using System;
        using System.Windows.Forms;
        
        namespace netframework
        {
            class Program
            {
                static void Main(string[] args)
                {
                    MyForm form = new MyForm();    // 事件响应者
                    form.ShowDialog();
                }
        
            }
        
            class MyForm : Form
            {
                private Button button;      // 事件拥有者
        
                public MyForm()
                {
                    this.button = new Button();
                    this.Controls.Add(this.button);
                    this.button.Click += this.ButtonClicked; // 事件  订阅  事件处理器
                }
        
                // 事件处理器
                private void ButtonClicked(object sender, EventArgs e)
                {
                    this.Text = DateTime.Now.ToString();
                }
            }
        }
        View Code
    •  事件的本质是委托字段的一个包装器
      • 这个包装器对委托字段的访问起限制作用
      • 封装的一个重要功能就是隐藏
      • 事件对外界隐藏了委托实例的大部分功能,仅暴露添加/移除事件处理器的功能
      • 添加/移除事件处理器的时候可以直接使用方法名,这是委托实例所不具备的
    • 用于声明事件的委托实例的命名约定
      • 用于声明Foo事件的委托,一般命名为FooEventHandler(除非是一个非常通用的事件约束)
      • FooEventHandle委托的参数一般由两个(由WIn32 API演化而来,历史悠久)
        • 第一个是object类型,名字为sender,实际上就是时间的拥有者、事件的source
        • 第二个是EventArgs类的派生类,类名一般为FooEventArgs,参数名为e。也就是前面讲的事件参数。
      • 触发Foo事件的方法一般命名为OnFoo,即因何引发
        • 访问级别为protected,不能public,不然又成了可以"借刀杀人"
    • 事件的命名约定
      • 带有时态的动词或者动词短语
      • 事件拥有者"正在做"什么事情,用进行时; 事件拥有者做完了什么事情,用完成时
    • 注意
      • 时间处理器是方法成员
      • 挂接处理器(使用+=挂接)的时候,可以使用委托实例,也可以直接使用方法名,这是个语法糖-
      • 事件处理器对事件的订阅不是随意的,匹配与否由声明事件时所使用的委托类型来检测
      • 事件可以同步调用也可以异步调用

     事件的声明(自定义声明)

    •  声明
      • 完整声明
        // 委托声明
        public
      • 简略声明

    快捷键:

    完整声明属性:propfull 两下tab

    简略声明属性:prop 两下tab

    索引器声明:indexer 两下tab

    visual studio中的图标: 小闪电--事件(一定条件下可以通知谁,通知别人),小方块---方法(能做什么,做事情), 小扳手--属性(处于什么状态,存储数据),类的最重要的三块。

  • 相关阅读:
    bodybuilding
    DBLINK的session无法关闭,报异常!
    失控
    eclipse
    Linux下查看用户列表
    org.apache.commons.httpclient
    java map 遍历
    java String split
    胸上肌到底要怎么练啊!
    POI操作Excel常用方法总结
  • 原文地址:https://www.cnblogs.com/MJ-CAT/p/12069472.html
Copyright © 2011-2022 走看看