首页 > 技术文章 > C# 面向对象编程基础

popodynasty 2021-06-01 18:58 原文

C# 面向对象编程基础

  1. C# 的成员修饰符
public 	  // 所有类都可以访问
private   // 只有本类可以访问。类的外部无法访问
internal  // 默认:同一个项目中的代码都可以访问,项目外的代码不能访问
protected // 奔类或其子类可以访问
protected internal
partial
sealed
static		// 静态成员能够通过类名调用
const		// 声明常量
readonly	// 可以在运行期间初始化一次, 以后不能修改
    
/*
简单说一下 const 和 readonly 的区别:
const修饰的为常量,其值能够在编译期间确定。
readonly修饰的为变量,其值能够在运行时确定,但初始化后不允许再进行修改。
*/
  1. C#的构造函数

    两种:实例构造函数、静态构造函数

    • 构造一个实例时,需要调用实例构造函数

    • 创造第一个实例或引用任何静态成员之前,都会自动调用静态构造函数。例如

      class SimpleClass{
          static readonly long baseline;
          static SimpleClass(){
              baseline = DateTime.Now.Ticks;
          }
      }
      
      /*
      - 静态构造函数没有访问修饰符,也没有参数
      - 静态构造函数在第一个实例构造函数之前执行
      - 不能显式调用静态构造函数
      - 静态构造函数只会调用一次
      */
      
  2. c# 的set与get

    和Java比较类似,加入我们要封装People类的age属性,以使得age最小为0,我们可以这么做

    // Java
    public class People{
        private int age;
        public void setAge(int age){
            if(age < 0) age = 0;
            this.age = age;
        }
        
        public void getAge(){
            return this.age;
        }
    }
    

    在C#中,我们也可以类似Java这种写法。此外,C#还提供了另一种途径,我们可以学习一下。

    // 写法1
    public class People
    {
        private int age = 0;
        public int Age
        {
        	get{
                return age;
            }
            set{
                if(value>=0 && value<=100) age = value;
            }
        }
    }
    // 写法2
    
    public class People
    {
        private int AgeStore; // 字段(Field) => 占用内存
        public int Age // 属性(Property) => 源于字段, 对字段的扩展, 经过逻辑处理, 不占用实际内存
        {
        	set
            {
                if(value < 0) value = 0;
                Age = value;
            }
            
            get
            {
            	return Age;    
            }
        }
    }
    
    1. 委托(Delegate)

      namespace DelegateTest
      {
          delegate <Tn> MyDelegate(<T1> a, <T2> b, <T3> c, .......)
          {
          	// do something
              return <Tn>
          }
      }
      // 定义委托的方法(并不严格遵循语法)
      // 一切返回值为 <Tn>类型的, 传入参数为(<T1>, <T2>, <T3>, ...) 类型的方法, 都可以‘委托’给 MyDelegateTest来调用。
      

      使用委托的例子:

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      
      namespace ConsoleApp1
      {
          class Program
          {
              delegate int MathOp1(ref int a);
              delegate int MathOp2(int a, int b);
              public class DelegateTest
              {
                  public static int Inc(ref int a)
                  {
                      a = a + 1;
                      return a;
                  }
      
                  public static int Add(int a, int b)
                  {
                      return a + b;
                  }
              }
              static void Main(string[] args)
              {
                  MathOp1 delegate_inc = new MathOp1(DelegateTest.Inc);
                  int a = 1;
                  int b = delegate_inc(ref a);
                  Console.WriteLine("a = {0}, b = {1}", a, b);
      
      
                  MathOp2 delegate_add = new MathOp2(DelegateTest.Add);
                  int c = 3;
                  int d = 5;
                  Console.WriteLine("c + d = {0}", delegate_add(c, d));
      
                  Console.ReadKey();
              }
          }
      }
      
    2. 事件(event)

      事件并非C#所特有,例如在Java中,点击一个按钮称为“点击”事件。

      C#预先定义了大量的事件,如click事件,我们也可以用event关键字来自定义事件。

      由于事件是和委托相关联的,因此声明事件之前需要先定义一个委托。

      public delegate void MyEventHandler();
      
      public event MyEventHandler handler;
      public void myFun(){......}
      a.handler += new MyEventHandler(a.myFun);
      

      我们大部分情况下都是使用系统预定义的事件,它们都统一具有标准的签名。
      返回类型为 void,具有两个参数 Object sender 和一个事件对象 e。
      系统为我们提供了现成的委托:

      public delegate void EventHandler(Object sender, EventArgs e);
      

      因此可以明白为什么系统的事件处理方法都是这样的形式。

推荐阅读