C#学习笔记22: 面向对象编程入门精讲

目录

1.1 官方编程文档

1.2 类与结构

1.3 引用类型与值类型

1.4 ref参数与out参数

1.5 方法重载

1.6 静态类与静态成员

1.7 继承与多态

1.9 抽象类与接口

1.10 拓展方法

1.11 委托与事件

1.12 枚举类型

1.13 数组


1.1 官方编程文档

C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC#\Specifications\2052\CSharp Language Specification.doc

1.2 类与结构

属性 描述对象的特征,也可对字段进行封装(get,set)
字段 类或结构体内部定义的变量
方法 类的某种动作或行为
构造器 构造函数,在创建实例对象时调用,来进行类的初始化工作
事件 特定条件下触发的行为

结构只能定义带参构造函数,不能继承和派生,但可以实现接口

结构中不能实例字段初始值

1.3 引用类型与值类型

类是引用类型

class Program
    {
        
        static void Main(string[] args)
        {
            person p1 = new person();
            person p2 = p1;

            p1.Name = "Jack";
            p1.Age = 30;

            Console.WriteLine(p2.Name + p2.Age.ToString());

            p1.Name = "Bob";
            p1.Age = 27;
            Console.WriteLine(p2.Name + p2.Age.ToString());
        }
    }
    class person
    {
        public string Name { set; get;}
        public int Age { set; get; }
    }

结构是值类型

    class Program
    {
        
        static void Main(string[] args)
        {
            person p1 = new person();
            person p2 = p1;

            p1.Name = "Jack";
            p1.Age = 30;

            Console.WriteLine(p2.Name + p2.Age.ToString());

            p1.Name = "Bob";
            p1.Age = 27;
            Console.WriteLine(p2.Name + p2.Age.ToString());
        }
    }
    struct person
    {
        public string Name { set; get;}
        public int Age { set; get; }
    }

C#学习笔记22: 面向对象编程入门精讲_第1张图片

引用对象与值对象的总结

C#学习笔记22: 面向对象编程入门精讲_第2张图片

1.4 ref参数与out参数

        static void getPerson1(person p)
        {
            p.Name = "Amiee";
            p.Age = 25;
        }
//此版本对参数p的操作会反应到实参中
        static void getPerson2(person p)
        {
            p = new person("Ray", 27);
        }
//此版本在传参数时,参数p指向的实参对象,但是进入函数后,参数p的指向发生了变化,对p参数的操作便不会再反映到实参中

上述两个函数的阐述传递过程如下:

C#学习笔记22: 面向对象编程入门精讲_第3张图片

为解决上述问题,引入ref参数和out参数:

ref参数传入前必须初始化,out传入前不用初始化

        static void getPerson3(ref person p)
        {
            p = new person("Ray", 28);
        }
        static void getPerson4(out person p)
        {
            p = new person("Ray", 29);
        }

均完成了对实参的修改

1.5 方法重载

具有不同返回值的同名方法可重载

具有不同参数个数、参数类型和参数顺序的同名方法

有无ref或out修饰符修饰的同名方法

1.6 静态类与静态成员

静态类的所有成员都必须的是静态的

类的静态成员可用类名直接调用

1.7 继承与多态

(1)可访问性

C#学习笔记22: 面向对象编程入门精讲_第4张图片

对internal可访问性的验证见博文https://blog.csdn.net/m1m2m3mmm/article/details/95667772

(2)继承

  • 子类构造时,线调用父类的构造函数再调用自己的构造函数;子类对象被销毁时,先调用自己的析构函数再调用父类的析构函数
  • 在继承时,子类的访问属性不高于父类的访问属性,比如基类是internal则不允许子类被定义为public

(3)覆盖与多态

  • 子类会自动覆盖基类中定义的非virtual关键字修饰的同名方法,但此时直接定义子类对象,调用的是子类的同名方法;若定义指向子类的父类对象,调用的是父类的同名方法;
  • 使用virtual关键字修饰的方法,在被指向子类的基类对象调用时,实际上调用的是子类对象的方法;直接定义子类对象时,调用的是子类自己的同名方法

(4)定义不可被继承的类

sealed class  ClassName
{
    
};

1.9 抽象类与接口

抽象类可以定义非抽象成员,这些成员被其派生类继承;抽象类的不能被实例化

非抽象类不能定义抽象成员

 

接口与抽象类的区别:【参考之前博文类与对象学习小结】

  • 接口是一种类型,不提供任何实现的代码,没有构造函数,接口定义的方法是不带任何访问关键字的
  • 抽象类的是类的一种,可以定义非抽象成员和构造函数,成员具有访问属性
  • 不允许一个类同时提供对多个基类 的实现;但允许一个接口同时实现多个接口
  • 实现接口时,必须对接口提供对接口所有成员的实现

接口的显式实现

在实际的开发过程中,如果多个接口定义命名的成员,而这些接口又同时被同一个类实现,此时为了避免成员之间的冲突,需提供对接口的显式实现,在方法调用时,只能通过定义接口进行调用;通过实现类对象无法进行调用,除非将其强制转化为对应的接口。

1.10 拓展方法

在不继承的前提下,对现有类型进行拓展;拓展方法定义在静态类中的静态方法

//拓展方法的定义   
     public static class stringExt//静态类,静态成员
    {
        //将字符串转化为空格分开的字符串
        public static string SplitSpace(this string str)
        {
            return string.Join(" ", str.ToCharArray());
        }
        //将数值转化为其绝对值
        public static int abs(this int num)
        {
            return num >= 0 ? num : 0 - num;
        }
    }

调用拓展方法


            string str = "Ray";          
            Console.WriteLine(str.SplitSpace()); //并不会对str的值产生任何影响,只是产生了一个新的空格分割字符串
            int num = -10;
            Console.WriteLine(num.abs().ToString());

1.11 委托与事件

  • 类似于C语言中的函数指针,C#也可以将函数当作方法传给其他方法
  • 定义委托与定义其他方法类似,不过需要使用关键字delagate关键字
  • 委托类型的隐含公共基类:System.Delagate和System.MulticastDelegate(多播委托);多播委托被调用,会调用与之关联的所有方法;
  • 当将委托当作参数传递某个方法时,是值类型的传递;在方法内部对引用的委托实例进行变更时,并不会反应到原来的委托实例中
  • 可以总结出委托使用的三个关键点:定义委托,委托实例化,委托调用

事件是委托类型,要声明事件就需要定义事件封装类型的委托;然后在类中使用event关键字,同时为了让派生类可以重写该事件,常将其定义为protected类型。习惯上,事件的命名方式为On<事件名>

以学生听到铃声就知道是下课为例,说明事件与委托的关系:铃声响,代表事件发生;学生知道下课就是对事件的响应

标准事件与委托

更为详细的分析见博文委托与事件

1.12 枚举类型

使用枚举类型的好处:

避免意外的调用,调用者只能在给定的值当中做出选择;

可读性强,调用可以方便的识别各枚举值代表的含义

枚举类型继承自Enum类,该类是ValueType类型的派生类,可知枚举类型属于值类型

enum week
{
     mondey,friday,sonday
}

枚举类型的基础类型为int,默认从0开始,后值在前值基础上+1

C#学习笔记22: 面向对象编程入门精讲_第5张图片

var myWeek = Enum.GetValues(typeof(week));//获取枚举类型中的所有值到一个对应类型的数组中
string name = Enum.GetName(typeof(week), 2);//sonday
string names = Enum.GetNames(typeof(week));//所有项

1.13 数组

声明与赋值

//先声明后赋值
type[] arr = new type[count];
arr[0] = value1;
arr[1] = value2;
//声明同时赋值
type[] arr = new type[] {valueList};
type[] arr = {valueType};


//二维数组
type[,] arr = new type[rowCount, colCount];
arr[0,0] = value00;
arr[0,1] = value01;

数组遍历

for(int i = 0; i < arr.Count; i++)
{
    Console.Writeline(arr[i].ToString());
}
//所有数组继承自IEnumerable,可以使用foreach遍历
foreach(type var in arr)
{
    Console.Writeline(var.ToString());
}
方法 描述 返回值
Array.Reverse(arr); 字符串反转 T[]
Array.Resize(arr, int newSize); 改变数组大小;哈希值会发生变化 T
Array.Find(arr, new Predicate(dealFun)); 从头查找满足某规则的值 T

Array.Findlast(arr, new Predicate(dealFun));

从尾部查找满足某规则的值 T
Array.FindAll(arr, new Predicate(dealFun)); 查找所有满足某规则的值 T[]

 

C#学习笔记22: 面向对象编程入门精讲_第6张图片 查找元素索引的方法

上述第二组方法需要用到Predicate委托,原型如下:

T为参数类型,obj为数组中待查找元素应满足条件的方法名

private static bool findProc(T obj)
{
    if(条件一)    
    {
        //处理代码1
        return ture;
    }
    if(条件二)
    {
        //处理代码2
        return false;
    }
}

 

 

你可能感兴趣的:(C#编程学习)