> 文章列表 > 【C#基础】C# 面向对象编程

【C#基础】C# 面向对象编程

【C#基础】C# 面向对象编程

序号 系列文章
5 【C#基础】C# 运算符总结
6 【C#基础】C# 常用语句讲解
7 【C#基础】C# 常用数据结构

文章目录

  • 前言
  • 面向对象的 C#
    • 1,类的概念
    • 2,类的定义
    • 3,类成员
    • 4,对象
    • 5,继承
    • 6,多态性
  • 结语

前言

😊大家好,我是writer桑,前面一章已经学习了 C# 中的常用数据结构,那本章就开始学习 C# 程序中面向对象编程的知识,希望看完大家能够有所收获,感谢支持!


面向对象的 C#

面向对象编程是一种计算机编程架构(Object Oriented Programming,简称OOP)。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。OOP的三大特征分别为封装、继承和多态。用公式概括为:OOP=对象+类+继承+多态+消息,其中核心概念是类和对象。 C# 就是一种面向对象的编程语言,完美实现了抽象、封装、继承和多态性的面向对象特性。

1,类的概念

类的创建就相当于生成了一个蓝图。在蓝图中指定该类可以进行哪些操作,也就是在类中创建指定字段、属性和方法成员。对象是类的实例,类对象的组成和操作都是由类决定的。 在 C# 程序中使用"访问修饰符"(可选)+ class 关键字 + "类的名称"来声明类。

示例如下:

public class Person		// 类名称的声明
{public string Name { get; set; }	// 成员属性 public int Age { get; set; }// 成员函数 public Person(string name, int age){Name = name;Age = age;}// 成员方法 public void MethodBody(){Console.WriteLine("Hello,World");}// 其他属性、方法、事件…… 
}

2,类的定义

C# 定义类使用唯一的标识符 class 。 类定义的语法可概括为 <access specifier> class class_name , 其中 <access specifier> 为访问修饰符,class_name 为类的名称,类名称必须符合 C# 的命名规范。

访问修饰符的概念和使用:

class 关键字前面前面是访问修饰符,示例中使用的是 public 修饰符 ,也可以是 public、private、protected、internal、protected internal 和 private protected,默认为 internal 。 这些访问修饰符分别表达的意思以一个表格来展示。

表格如下:

访问修饰符 描述
public 同一程序集中的任何其他代码或引用该程序集的其他程序集都可以访问该类型或成员。 某一类型的公共成员的可访问性水平由该类型本身的可访问性级别控制。
private 只有同一 class 或 struct 中的代码可以访问该类型或成员。
protected 只有同一 class 或者从该 class 派生的 class 中的代码可以访问该类型或成员。
internal 同一程序集中的任何代码都可以访问该类型或成员,但其他程序集中的代码不可以。 换句话说,internal 类型或成员可以从属于同一编译的代码中访问。
protected internal 该类型或成员可由对其进行声明的程序集或另一程序集中的派生 class 中的任何代码访问。
private protected 该类型或成员可以通过从 class 派生的类型访问,这些类型在其包含程序集中进行声明。

抽象类的概念和使用:

使用 abstract 关键字可以创建不完整且必须在派生类中实现的类和 class 成员,称为抽象方法。 C# 规定抽象方法的实现必须放在抽象类中。抽象类不能实例化,抽象类的用途就是提供一个可供多个派生类共享的通用基类定义。通过在类定义前面放置 abstract 修饰符将其声明为抽象类。

示例如下:

using System;public abstract class AbstProgram            // 必须声明为抽象类 
{public abstract string abstMethod();     // 抽象方法}public class Subclass : AbstProgram
{// 抽象方法必须实现public override string abstMethod(){return "hello,abstMethod";}
}

密封类的概念和使用:

使用 sealed 修饰符应用于某个类时,这个类称为密封类。密封类可以阻止其他类继承自该类,还可以对替代基类中的虚方法或属性的方法或属性使用 sealed 修饰符。这使得类派生自你的类并防止它们替代特定虚方法或属性。

示例如下:

using System; public class Program
{public virtual void virmethod()          // 虚方法 {Console.WriteLine("hello,virmethod");}
}public sealed class SealClass : Program      // 密封类 
{public override sealed void virmethod(){Console.WriteLine("hello, sealed");}
}

静态类的概念和使用:

类的声明可以添加 static 修饰符声明为静态类。 静态类只能包含静态成员,不能使用 new 关键字字进行实例化。 静态类基本上与非静态类相同,但有一个区别就是静态类无法被实例化。由于不存在任何实例变量,因此可以使用类名本身访问静态类的成员。

示例如下:

using System;// 静态类 
static class StaticMethod
{public static int number = 4;public static int getNumber(){return number; }
}; public class Program
{static void Main(string[] args){Console.WriteLine(StaticMethod.getNumber()); }
}

3,类成员

类的成员包括在类中声明的所有成员, 以及在该类中的继承层次结构中的所有类中声明的所有成员(构造函数和析构函数除外)。 注意基类中的私有成员被继承,但是不能从派生类中访问。 在类中定义的字段、属性、方法和事件都可以称为类成员。

字段和属性的概念与使用:

字段也就是在类范围声明的变量,字段可以是内置数值类型或其他类的实例。 属性是类中可以像类中的字段一样访问的方法。属性可以为类字段提供保护,以避免字段在对象不知道的情况下被更改。

示例如下:

using System; public class Person
{public int age;     // 字段的声明 // 属性的声明 public int Age{set{if(value > 0 && value < 100){age = value;}}get {return age;}}
}

字段和属性的区别:

  • 属性相当于在类中的变量,而字段具备 set 和 get 的操作。
  • 读取字段的值时,程序走的是 get{} 操作;给字段赋值时,程序走的是 get{} 操作。
  • 当想让字段不被赋值时,可以只写get{} 操作,不写 set{} 操作。

构造函数和析构函数的概念与使用:

构造函数是一个特殊的成员函数,是在首次创建类对象时执行的方法,它们通常用于初始化对象的数据。构造函数的名称和类的名称完全相同,且没有任何返回类型。 折构函数也是类的一个特殊的成员函数, 是在类的对象超出范围时执行,通常用于结束程序(比如关闭文件、释放内存等)之前释放资源。折构函数在类名称前面加一个 ~ 前缀进行声明,而且不具备任何返回值和参数。

示例如下:

using System; public class Person
{private string last;private string first;// 构造函数的声明并且初始化类字段public Person(string lastName, string firstName){last = lastName;first = firstName;}
} 
using System;class Person
{private int age;// 构造函数 public Person()  {Console.WriteLine("对象已创建");}//析构函数~Person() {Console.WriteLine("对象已删除");}
}

类方法的概念和使用:

方法是包含一系列语句的代码块,类方法定义类可以执行的操作。程序通过调用该方法并指定任何所需的方法参数使语句得以执行。方法可接收提供输入数据的参数,并可通过参数返回输出数据。方法也可以不使用参数而直接返回值。 使用 “访问修饰符” + “返回数据类型” + “方法名称” 的格式来声明类方法。

示例如下:

public class Person
{// 成员方法 public void MethodBody(){Console.WriteLine("Hello,World");   // "Hello,World"}
}

虚方法的概念和使用:

虚方法也就是可以被派生类重写的方法,如果派生类重写基类中的虚方法,则在运行时将运行重写的行为。但是如果派生类没有重写虚方法,则运行时执行基类中的虚方法行为。 在 C## 程序中,使用 virtual 关键字来声明虚方法。

示例如下:

public class Rectangular
{// 虚方法public virtual double Area(int x, int y){return x * y;} 
}public class Program : Rectangular
{// 重写虚方法 public override double Area(int x, int y){return x * y;}
}

抽象方法的概念和使用:

抽象方法也是可以被派生类重写的方法,但是和虚方法不同的是抽象方法是强制派生类重写的方法, 否则派生类就不能实例化。 抽象方法只能在抽象类中声明,可以使用 abstract 修饰符进行声明。 抽象方法只有方法名称, 没有方法实现。

示例如下:

public abstract class Animal
{// 抽象方法的声明 public abstract void Sleep();public abstract void Eat();
}public class Person : Animal
{// 必须实现基类中的抽象方法public override void Eat(){throw new NotImplementedException();}public override void Sleep(){throw new NotImplementedException();}
}

点击了解虚方法和抽象方法的异同,整理第一条。

4,对象

对于面向对象的编程语言,一切皆为对象,对象是程序的基本单元。对象把程序与数据封装起来提供对外访问的能力,提高软件的重用性,灵活性和扩展性。前面说过类或结构定义的作用类似于蓝图 ,指定着该类或结构可以进行哪些操作。 而类的对象是此蓝图分配和配置的内存块。

创建类对象的操作:

C# 程序允许同一个类实例化出多个对象。 可以通过这些对象来操作类中的方法、字段与属性等类成员。可以使用 new 运算符创建类对象,同时指定对象的名称和类型参数。

示例如下:

public class Person
{public string Name { get; set; }public int Age { get; set; }public Person(string name, int age){Name = name;Age = age;}
}class Program
{static void Main(){// 创建对象 person1 Person person1 = new Person("Leopold", 6);Console.WriteLine($"person1 Name = {person1.Name} Age = {person1.Age}");}
}
/*输出:person1 Name = Leopold Age = 6
*/

对象的标识与值相等性:

当比较两个对象是否相等时,首先必须明确是想知道两个对象是否是同一个引用,还是这两个对象一个或多个字段的值是否相等。如果是前者,可使用静态 Object.Equals 方法。 如果是后者,可以使用 Equals 方法或 == 运算符。

示例如下:

Person p1 = new Person("Wallace", 75);
Person p2 = p1; if (p2.Equals(p1))Console.WriteLine("p2和p1有相同的值。");if (p1.Name == p2.Name)Console.WriteLine("p1和p2的Name属性相等。"); 

5,继承

继承是面向对象编程的三大特征之一。通过继承,可以重用、扩展和修改被继承类的行为。其中被继承的类称为"基类",继承这些基类的类称为派生类。 虽然派生类只能有一个直接基类,但是继承之间是可以传递的。 比方说 ClassC 派生自 ClassB,并且 ClassB 派生自 ClassA,则 ClassC 将继承在 ClassB 和 ClassA 中声明的成员。

继承的使用:

class 关键字前面的是类的名称。 在示例中类的名称为 Person 。类(而非结构)支持继承的概念。派生自另一个类(称为基类)的类自动包含基类的所有公共、受保护和内部成员(其构造函数和终结器除外)。 在 C# 程序中使用 :标识符来声明要继承的父类。

示例如下:

public class Animal
{public static void animalMethod(){Console.WriteLine("这是Animal类的方法");}
}public class Person : Animal   // 继承父类 Animal
{ static void Main(string[] args){animalMethod();     // 这是Animal类的方法}
}

多重继承的示例:

using System;// 这是基类 Shape 
public class Shape
{public void setWidth(int w){width = w;}public void setHeight(int h){height = h;}protected int width;protected int height;
}// 这是接口 PaintCost
public interface PaintCost
{int getCost(int area);}// 派生类继承基类 Shape 和接口 PaintCost
public class Rectangle : Shape, PaintCost
{public int getArea(){return (width * height);}// 实现接口中的方法 public int getCost(int area){return area * 70;}
}public class RectangleTester
{static void Main(string[] args){Rectangle Rect = new Rectangle();int area;Rect.setWidth(5);Rect.setHeight(7);area = Rect.getArea();// 打印对象的面积Console.WriteLine("总面积: {0}", Rect.getArea());Console.WriteLine("油漆总成本: ${0}", Rect.getCost(area));Console.ReadKey();}
}

接口的概念和使用:

类不仅可以继承父类,还可以继承接口。C# 的接口义了所有类或者结构体继承接口时应实现的一组相关功能的定义。 接口中可以定义属性、方法和事件,这些都是接口的成员。但是接口不能声明实例数据,如字段、自动实现的属性或类似属性的事件。接口只包含了成员的声明,而成员的实现是派生类的任务,一个派生类支持继承多个接口,接口也可以继承其它接口。使用 interface 修饰符来声明一个接口。

示例如下:

interface IMyInterface       // 声明接口 IMyInterface 
{public void intMethod();    // 接口定义的方法
}public class Person : IMyInterface	// Person 类继承接口 IMyInterface 
{public void intMethod()    // 实现接口的方法{throw new NotImplementedException();}
}

点击了解抽象类和接口的异同,第二条整理。

6,多态性

多态性常被视为自封装和继承之后,面向对象编程的第三个支柱。 多态性表示当同一操作作用于不同的对象时,可以有不同的行为,返回多种执行结果。在实际的应用中,多态性常表现为“一个接口,多个功能。 C# 的多态性可以是静态的或者动态的。 在静态多态性中,函数的响应是在编译时发生的。在动态多态性中,函数的响应是在运行时发生的。

静态多态性:

编译时的多态性是通过重载实现的, 对于非虚的成员, 系统在编译时会根据传递的参数、返回的类型等信息决定实现何种操作。在编译期间,函数和对象的连接机制被称为早期绑定,也被称为静态绑定。C# 提供了两种技术来实现静态多态性,分别为函数重载运算符重载。 以函数重载为示例,点击了解运算符重载。

示例如下:

using System;public class TestData
{ // 函数重载 public int Add(int a, int b, int c){return a + b + c;}public int Add(int a, int b){return a + b;}
}class Program
{static void Main(string[] args){TestData dataClass = new TestData();int add1 = dataClass.Add(1, 2);int add2 = dataClass.Add(1, 2, 3);Console.WriteLine("add1 :" + add1);Console.WriteLine("add2 :" + add2);}
}

动态多态性:

除了静态多态性外,还有动态多态性。也即只有到系统运行时,程序才根据实际情况实现具体行为。C# 支持的动态多态性可以通过重写基类中抽象方法和虚方法来实现。

抽象方法的示例:

using System;abstract class Shape
{// 声明抽象方法abstract public int area();
}class Rectangle : Shape
{private int length;private int width;// 声明构造函数 public Rectangle(int a = 0, int b = 0){length = a;width = b;}// 重写父类的抽象方法 public override int area(){Console.WriteLine("Rectangle 类的面积:");return (width * length);}
}class RectangleTester
{static void Main(string[] args){Rectangle r = new Rectangle(10, 7);double a = r.area();Console.WriteLine("面积: {0}", a);Console.ReadKey();}
}

虚方法的示例:

using System;
using System.Collections.Generic;public class Animal
{// 虚方法public virtual void Run(){Console.WriteLine("执行动物跑的行为");}
}class Cat : Animal
{// 重写基类Animal中的Run方法 public override void Run(){Console.WriteLine("猫在跑");base.Run();}
}class Dog : Animal
{public override void Run(){Console.WriteLine("狗在跑");base.Run();}
}class Pig : Animal
{public override void Run(){Console.WriteLine("猪在跑");base.Run();}
}class Program
{static void Main(string[] args){// 创建一个 List<Animal> 对象,并向该对象添加 Cat、Pig 和 Dogvar shapes = new List<Animal>{new Dog(),new Pig(),new Cat()};// 使用 foreach 循环对该列表的派生类进行循环访问,并对其中的每个 Animal 对象调用 Run 方法foreach (var shape in shapes){shape.Run();}Console.WriteLine("按下任意键退出。");Console.ReadKey();}}

结语

🌟 以上就是 C# 面向对象编程知识点的介绍,希望能够对大家有所帮助。望大家多多支持,你们的支持就是笔者创作最大的动力!

MSDN工具