面向对象(C#基础)

面向对象(C#基础)

类和对象

类和对象

C# 中的一切都与类和对象及其属性和方法相关联。例如:在现实生活中,汽车是一个物体。汽车有属性,比如重量和颜色,还有方法,比如驱动和刹车。

类类似于对象构造函数,或用于创建对象的"蓝图"。

创建一个类

要创建类,请使用class关键字:

创建一个名为"Car"且color颜色可变的类:

class Car 
{
  string color = "red";
}

当变量直接在类中声明时,它通常被称为字段(或属性)。

它不是必需的,但是在命名类时,最好从大写的第一个字母开始。而且C#文件名和类名匹配是很常见的,因为它使我们的代码有条理。但是它不是必需的(就像在Java中一样)。

创建对象

对象是从类创建的。我们已经创建了名为Car的类,所以现在可以使用它来创建对象。

要创建Car的对象,请指定类名,后跟对象名,并使用关键字new

  • 实例

创建一个名为"myObj"的对象,并使用它打印color颜色值:

class Car 
{
  string color = "red";

  static void Main(string[] args)
  {
    Car myObj = new Car();
    Console.WriteLine(myObj.color);
  }
}

注意,我们使用点语法(.)来访问类中的变量/字段(myObj.color)

多个对象

可以创建一个类的多个对象:

  • 实例

创建两个Car对象:

class Car
{
  string color = "red";
  static void Main(string[] args)
  {
    Car myObj1 = new Car();
    Car myObj2 = new Car();
    Console.WriteLine(myObj1.color);
    Console.WriteLine(myObj2.color);
  }
}

使用多个类

还可以创建类的对象并在另一个类中访问它。

这通常用于更好的类组织(一个类具有所有字段和方法,而另一个类则持有Main()方法(要执行的代码))。

  • Car.cs
class Car 
{
public string color = "red";
}
  • Program.cs
class Program
{
static void Main(string[] args)
{
 Car myObj = new Car();
 Console.WriteLine(myObj.color);
}
}

类成员

类成员

类中的字段和方法通常称为"类成员":

  • 实例

创建一个包含三个类成员的Car类:两个字段和一个方法。

// 类
class MyClass
{
  // 类成员
  string color = "red";        // 字段
  int maxSpeed = 200;          // 字段
  public void fullThrottle()   // 方法
  {
    Console.WriteLine("The car is going as fast as it can!");
  }
}

字段

在上一章中,了解到类中的变量称为字段,可以通过创建类的对象和使用点语法(.)来访问它们。

下面的示例将创建一个名为myObjCar类对象。然后打印颜色color和最大速度maxSpeed字段的值:

class Car 
{
string color = "red";
int maxSpeed = 200;

static void Main(string[] args)
{
 Car myObj = new Car();
 Console.WriteLine(myObj.color);
 Console.WriteLine(myObj.maxSpeed);
}
}

也可以将字段保留为空,并在创建对象时对其进行修改:

class Car 
{
string color;
int maxSpeed;

static void Main(string[] args)
{
 Car myObj = new Car();
 myObj.color = "red";
 myObj.maxSpeed = 200;
 Console.WriteLine(myObj.color);
 Console.WriteLine(myObj.maxSpeed);
}
}

这在创建一个类的多个对象时特别有用:

class Car 
{
string model;
string color;
int year;

static void Main(string[] args)
{
 Car Ford = new Car();
 Ford.model = "Mustang";
 Ford.color = "red";
 Ford.year = 1969;

 Car Opel = new Car();
 Opel.model = "Astra";
 Opel.color = "white";
 Opel.year = 2005;

 Console.WriteLine(Ford.model);
 Console.WriteLine(Opel.model);
}
}

对象方法

方法通常属于类,它们定义类的对象的行为方式。

与字段一样,可以使用点语法访问方法。但是请注意,该方法必须是公共的public。请记住,我们使用方法的名称后跟两个paranthese()和一个分号;来调用(执行)该方法:

class Car 
{
string color;                 // 字段
int maxSpeed;                 // 字段
public void fullThrottle()    // 方法
{
 Console.WriteLine("The car is going as fast as it can!"); 
}

static void Main(string[] args)
{
 Car myObj = new Car();
 myObj.fullThrottle();  // 调用方法
}
}

为什么我们要声明这个方法是公共的public,而不是静态的static?

原因很简单:不创建类的对象就可以访问静态方法static,而公共方法public只能由对象访问。

使用多个类

记住上一章,我们可以使用多个类来更好地组织(一个用于字段和方法,另一个用于执行)。建议:

Car.cs

class Car 
{
public string model;
public string color;
public int year;
public void fullThrottle()
{
 Console.WriteLine("The car is going as fast as it can!"); 
}
}

Program.cs

class Program
{
static void Main(string[] args)
{
 Car Ford = new Car();
 Ford.model = "Mustang";
 Ford.color = "red";
 Ford.year = 1969;

 Car Opel = new Car();
 Opel.model = "Astra";
 Opel.color = "white";
 Opel.year = 2005;

 Console.WriteLine(Ford.model);
 Console.WriteLine(Opel.model);
}
}

public关键字称为访问修饰符,它指定Car的字段对于其他类(如 Program)也是可访问的。

构造函数

构造函数

构造函数是用于初始化对象的特殊方法。构造函数的优点是在创建类的对象时调用它。它可用于设置字段的初始值:

创建一个构造函数:

// 创建 Car 类
class Car
{
public string model;  // 创建一个字段

// 为 Car 类创建一个类构造函数
public Car()
{
 model = "Mustang"; // 设置 model 的初始值
}

static void Main(string[] args)
{
 Car Ford = new Car();  // 创建 Car 类的对象(这将调用构造函数)
 Console.WriteLine(Ford.model);  // 打印 model 的值
}
}

// 输出 "Mustang"

请注意,构造函数名称必须与类名匹配,并且不能有返回类型(如void或int)。

还要注意,在创建对象时会调用构造函数。

默认情况下,所有类都有构造函数:如果不自己创建类构造函数,C# 将创建一个。但是,不能为字段设置初始值。

节省开发者时间! 看看这一页的最后一个例子来真正理解原因。

构造函数参数

构造函数还可以接受参数,用于初始化字段。

下面的示例向构造函数添加一个字符串参数string modelName。在构造函数中,我们将model设置为modelName(model=modelName)。当我们调用构造函数时,我们将一个参数传递给构造函数("Mustang"),它将model的值设置为"Mustang"

class Car
{
public string model;

// 创建一个带参数的类构造函数
public Car(string modelName)
{
 model = modelName;
}

static void Main(string[] args)
{
 Car Ford = new Car("Mustang");
 Console.WriteLine(Ford.model);
}
}

// 输出 "Mustang"

可以有任意多个参数:

class Car
{
public string model;
public string color;
public int year;

// 创建具有多个参数的类构造函数
public Car(string modelName, string modelColor, int modelYear)
{
 model = modelName;
 color = modelColor;
 year = modelYear;
}

static void Main(string[] args)
{
 Car Ford = new Car("Mustang", "Red", 1969);
 Console.WriteLine(Ford.color + " " + Ford.year + " " + Ford.model);
}
}


// 输出 Red 1969 Mustang

提示: 与其他方法一样,构造函数可以通过使用不同数量的参数来重载

访问修饰符

访问修饰符

现在,已经非常熟悉我们的许多示例中出现的public关键字:

public string color;

public 关键字是一个访问修饰符,用于设置类、字段、方法和属性的访问级别/可见性。

  • C# 具有以下访问修饰符:
修饰符描述
public所有类都可以访问该代码
private代码只能在同一类中访问
protected代码可以在同一类中访问,也可以在从该类继承的类中访问。将在后面的章节中了解有关继承inheritance 的更多信息
internal代码只能在它自己的程序集中访问,而不能从另一个程序集中访问。将在后面的一章中了解更多

还有两种组合:内部保护protected internal和私有保护private protected

现在,让我们集中讨论公共public修饰符和私有private修饰符。

私有修饰符

如果使用私有private访问修饰符声明字段,则只能在同一类中访问该字段:

class Car
{
  private string model;

  static void Main(string[] args)
  {
    Car Ford = new Car("Mustang");
    Console.WriteLine(Ford.model);
  }
}

输出将是:

Mustang

如果尝试在类外访问它,则会发生错误:

class Car
{
private string model = "Mustang";
}

class Program
{
static void Main(string[] args)
{
 Car myObj = new Car();
 Console.WriteLine(myObj.model);
}
}

输出将是:

'Car.model' is inaccessible due to its protection level 

The field 'Car.model' is assigned but its value is never used

公共访问修饰符

如果使用公共public 访问修饰符声明字段,则所有类都可以访问该字段:

class Car
{
  public string model = "Mustang";
}

class Program
{
  static void Main(string[] args)
  {
    Car myObj = new Car();
    Console.WriteLine(myObj.model);
  }
}

输出将是:

Mustang

为什么选择访问修饰符?

控制类成员的可见性(每个单独类和类成员的安全级别)。

实现封装"Encapsulation"——即确保对用户隐藏敏感数据的过程。这是通过将字段声明为private来实现的。

注释: 默认情况下,如果不指定访问修饰符,则类的所有成员都是私有的private

class Car
{
string model;  // private
string year;   // private
}

C# 属性 (Get 和 Set)

属性和封装

在我们开始解释属性之前,应该对封装"Encapsulation"有一个基本的了解。

封装的意义是确保对用户隐藏敏感数据。为此必须:

  • 将字段/变量声明为私有 private
  • 通过属性提供公共字段public的值,通过getset方法来访问和更新私有字段private

属性

private私有变量只能在同一个类中访问(外部类不能访问它)。但是,有时我们需要访问它们,这可以通过属性来完成。

属性类似于变量和方法的组合,它有两种方法:getset方法:

class Person
{
private string name; // 字段

public string Name   // 属性
{
 get { return name; }   // get 方法
 set { name = value; }  // set 方法
}
}

实例解析

Name属性与name字段相关联。好的做法是对属性和私有字段使用相同的名称,但首字母大写。

get 方法返回变量名name的值。

set 方法为name变量赋值。value关键字表示我们分配给属性的值。

现在我们可以使用Name属性来访问和更新Person类的private字段:

class Person
{
private string name; // 方法
public string Name   // 属性
{
 get { return name; }
 set { name = value; }
}
}

class Program
{
static void Main(string[] args)
{
 Person myObj = new Person();
 myObj.Name = "Liam";
 Console.WriteLine(myObj.Name);
}
}

输出为:

Liam

自动属性(简写)

C#还提供了一种使用简写/自动属性的方法,不必为属性定义字段,只需在属性内部编写 get;set;

下面的示例将产生与上面示例相同的结果。唯一的区别是代码更少:

class Person
{
  public string Name  // property
  { get; set; }
}

class Program
{
  static void Main(string[] args)
  {
    Person myObj = new Person();
    myObj.Name = "Liam";
    Console.WriteLine(myObj.Name);
  }
}

输出将是:

Liam

为什么要用封装?

  • 更好地控制类成员(减少自己(或他人)弄乱代码的可能性)
  • 字段可以设置为只读(如果只使用get方法),也可以设置为只读(如果只使用set方法)
  • 灵活:程序员可以更改代码的一部分而不影响其他部分
  • 提高了数据的安全性

继承

继承(派生类和基类)

在 C# 中,可以将字段和方法从一个类继承到另一个类。我们将继承概念分为两类:

  • 派生类(子类)-从另一个类继承的类
  • 基类(父级)-从中继承的类

要从类继承,请使用:符号。

在下面的示例中Car类(child)从Vehicle类(parent)继承字段和方法:

class Vehicle  // 基类(父类)
{
public string brand = "Ford";  // Vehicle 字段
public void honk()             // Vehicle 方法 
{                    
 Console.WriteLine("Tuut, tuut!");
}
}

class Car : Vehicle  // 派生类(子)
{
public string modelName = "Mustang";  // Car 字段
}

class Program
{
static void Main(string[] args)
{
 // 创建一个 myCar 对象
 Car myCar = new Car();

 // 在 myCar 对象上调用 honk() 方法(来自 Vehicle 类)
 myCar.honk();

 // 显示品牌字段的值(来自 Vehicle 类)和来自 Car 类的 modelName 的值
 Console.WriteLine(myCar.brand + " " + myCar.modelName);
}
}
  • 何时使用继承?

它对代码的可重用性很有用:在创建新类时重用现有类的字段和方法。

多态

多态性和重写方法

多态性意味着"许多形式",当我们有许多类通过继承相互关联时,多态性就会出现。

继承允许我们从另一个类继承字段和方法。多态性使用这些方法来执行不同的任务。这允许我们以不同的方式执行单个操作。

例如一个名为Animal的基类,它有一个名为animalSound()的方法。衍生的动物可以是猪、猫、狗、鸟,它们也有自己的动物声音(猪叫声,猫叫等)的实现:

class Animal  // 基类(父类)
{
public void animalSound() 
{
 Console.WriteLine("The animal makes a sound");
}
}

class Pig : Animal  // 派生类(子)
{
public void animalSound() 
{
 Console.WriteLine("The pig says: wee wee");
}
}

class Dog : Animal  // 派生类(子)
{
public void animalSound() 
{
 Console.WriteLine("The dog says: bow wow");
}
}

现在我们可以创建PigDog对象,并对它们调用animalSound()方法:

class Animal  // 基类(父类)
{
public void animalSound() 
{
 Console.WriteLine("The animal makes a sound");
}
}

class Pig : Animal  // 派生类(子)
{
public void animalSound() 
{
 Console.WriteLine("The pig says: wee wee");
}
}

class Dog : Animal  // 派生类(子)
{
public void animalSound() 
{
 Console.WriteLine("The dog says: bow wow");
}
}

class Program 
{
static void Main(string[] args) 
{
 Animal myAnimal = new Animal();  // 创建一个 Animal 对象
 Animal myPig = new Pig();  // 创建 Pig 对象
 Animal myDog = new Dog();  // 创建 Dog 对象

 myAnimal.animalSound();
 myPig.animalSound();
 myDog.animalSound();
}
}

输出将是:

 The animal makes a sound
 The animal makes a sound
 The animal makes a sound
  • 为什么不是我要的结果?

上面示例的输出可能不是所期望的。这是因为基类方法在派生类方法共享相同名称时覆盖了它们。

但是,C#提供了一个重写基类方法的选项,方法是将virtual关键字添加到基类内的方法,并对每个派生类方法使用override关键字:

class Animal  // 基类(父类)
{
public virtual void animalSound() 
{
 Console.WriteLine("The animal makes a sound");
}
}

class Pig : Animal  // 派生类(子)
{
public override void animalSound() 
{
 Console.WriteLine("The pig says: wee wee");
}
}

class Dog : Animal  // 派生类(子)
{
public override void animalSound() 
{
 Console.WriteLine("The dog says: bow wow");
}
}

class Program 
{
static void Main(string[] args) 
{
 Animal myAnimal = new Animal();  // 创建一个 Animal 对象
 Animal myPig = new Pig();  // 创建 Pig 对象
 Animal myDog = new Dog();  // 创建 Dog 对象

 myAnimal.animalSound();
 myPig.animalSound();
 myDog.animalSound();
}
}

输出将是:

 The animal makes a sound
 The pig says: wee wee
 The dog says: bow wow

为什么使用"继承"和"多态"?

它对代码的可重用性很有用:在创建新类时重用现有类的字段和方法。

抽象类

抽象类和方法

数据抽象是隐藏某些细节并只向用户显示基本信息的过程。
抽象可以通过抽象类接口来实现(将在下一章了解更多)。

abstract关键字用于类和方法:

  • 抽象类:是一个受限类,不能用于创建对象(要访问它,必须从另一个类继承)。
  • 抽象方法:只能在抽象类中使用,并且它没有主体。主体由派生类(继承自)提供。

抽象类可以有抽象方法和正则方法:

abstract class Animal 
{
public abstract void animalSound();
public void sleep() 
{
 Console.WriteLine("Zzz");
}
}

从上面的例子中,无法创建 Animal 类的对象:

Animal myObj = new Animal(); // 会产生错误(无法创建抽象类或接口'Animal'的实例)

要访问抽象类,它必须从另一个类继承。 让我们将我们在多态性一章中使用的Animal类转换为一个抽象类。

记得在继承章节中我们使用:符号来继承一个类, 并且我们使用 override 关键字来覆盖基类方法。

// 抽象类
abstract class Animal
{
// 抽象方法(没有主体)
public abstract void animalSound();
// 常规方法
public void sleep()
{
 Console.WriteLine("Zzz");
}
}

// 派生类(继承自 Animal)
class Pig : Animal
{
public override void animalSound()
{
 // 这里提供了 animalSound() 的主体
 Console.WriteLine("The pig says: wee wee");
}
}

class Program
{
static void Main(string[] args)
{
 Pig myPig = new Pig(); // 创建 Pig 对象
 myPig.animalSound();  // 调用抽象方法
 myPig.sleep();  // 调用常规方法
}
}
  • 为什么使用抽象类和方法?

为了实现安全性-隐藏某些细节,只显示对象的重要细节。

注释: 抽象也可以通过接口来实现,

接口

接口

在 C# 中实现抽象的另一种方法是使用接口。

接口是一个完全抽象类,它只能包含抽象方法和属性(具有空体):

// 接口
interface Animal 
{
void animalSound(); // 接口方法(没有主体)
void run(); // 接口方法(没有主体)
}

在接口的开头用字母"I"开头被认为是一种好的做法,因为这样可以更容易记住它是一个接口而不是一个类。

默认情况下,接口的成员是抽象的abstract和公共的public

注释: 接口可以包含属性和方法,但不能包含字段。

要访问接口方法,接口必须由另一个类实现(类似于继承)。要实现接口,请使用:符号(与继承一样)。接口方法的主体由"implement"类提供。 注意,在实现接口时,不必使用override 关键字:

// 接口
interface IAnimal 
{
void animalSound(); // 接口方法(没有主体)
}

// Pig "实现"了 IAnimal 接口
class Pig : IAnimal 
{
public void animalSound() 
{
 // 这里提供了 animalSound() 的主体
 Console.WriteLine("The pig says: wee wee");
}
}

class Program 
{
static void Main(string[] args) 
{
 Pig myPig = new Pig();  // 创建 Pig 对象
 myPig.animalSound();
}
}

接口说明:

  • 抽象类一样,接口不能用于创建对象(在上面的示例中,不可能在Program类中创建"IAnimal"对象)
  • 接口方法没有主体-主体由"implement"类提供
  • 在实现接口时,必须重写其所有方法
  • 接口可以包含属性和方法,但不能包含字段/变量
  • 默认情况下,接口成员是抽象的abstract和公共的public
  • 接口不能包含构造函数(因为它不能用于创建对象)

为什么以及何时使用接口?

\1) 为了实现安全性-隐藏某些细节,只显示对象(接口)的重要细节。

\2) C#不支持多重继承(一个类只能从一个基类继承)。但是,它可以通过接口实现,因为类可以实现多个接口。注释:要实现多个接口,请用逗号分隔它们(参见下面的示例)。

多个接口

要实现多个接口,请用逗号分隔它们:

interface IFirstInterface 
{
  void myMethod(); // 接口方法
}

interface ISecondInterface 
{
  void myOtherMethod(); // 接口方法
}

// 实现多个接口
class DemoClass : IFirstInterface, ISecondInterface 
{
  public void myMethod() 
  {
    Console.WriteLine("Some text..");
  }
  public void myOtherMethod() 
  {
    Console.WriteLine("Some other text...");
  }
}

class Program 
{
  static void Main(string[] args)
  {
    DemoClass myObj = new DemoClass();
    myObj.myMethod();
    myObj.myOtherMethod();
  }
}

C# 枚举

枚举

枚举enum是一个特殊的类"class",它表示一组常量(不可更改/只读变量)。

要创建枚举enum,请使用enum关键字(而不是class或interface),并用逗号分隔枚举项:

enum Level 
{
  Low,
  Medium,
  High
}

你可以使用**.**点语法访问枚举:

Level myVar = Level.Medium;
Console.WriteLine(myVar);

Enum 是 “enumerations” 的缩写,意思是特别列出的。

类内枚举

类中还可以有枚举enum

class Program
{
  enum Level
  {
    Low,
    Medium,
    High
  }
  static void Main(string[] args)
  {
    Level myVar = Level.Medium;
    Console.WriteLine(myVar);
  }
}

输出为:

  Medium

枚举值

默认情况下,枚举的第一项的值为0,第二个值为1,依此类推。

要从项中获取整数值,必须将该项显式转换为int

enum Months
{
January,    // 0
February,   // 1
March,      // 2
April,      // 3
May,        // 4
June,       // 5
July        // 6
}

static void Main(string[] args)
{
int myNum = (int) Months.April;
Console.WriteLine(myNum);
}

输出将是:

3

还可以指定自己的枚举值,接下来的项目将相应地更新该数字:

enum Months
{
January,    // 0
February,   // 1
March=6,    // 6
April,      // 7
May,        // 8
June,       // 9
July        // 10
}

static void Main(string[] args)
{
int myNum = (int) Months.April;
Console.WriteLine(myNum);
}

输出将是:

7

Switch 语句中的枚举

枚举通常在switch语句中用于检查相应的值:

enum Level 
{
  Low,
  Medium,
  High
}

static void Main(string[] args) 
{
  Level myVar = Level.Medium;
  switch(myVar) 
  {
    case Level.Low:
      Console.WriteLine("Low level");
      break;
    case Level.Medium:
       Console.WriteLine("Medium level");
      break;
    case Level.High:
      Console.WriteLine("High level");
      break;
  }
}

输出将是:

 Medium level 

为什么以及何时使用枚举?

当知道值不会更改时,可以使用枚举,比如月份、星期、颜色、卡片组等。

  • 20
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值