讲解C#面相对象编程中的类与对象的特性与概念

 更新时间:2020年6月25日 11:25  点击:2128


“类”是一种构造,通过使用该构造,您可以将其他类型的变量、方法和事件组合在一起,从而创建自己的自定义类型。类就像一个蓝图,它定义类型的数据和行为。如果类没有声明为静态类,客户端代码就可以创建赋给变量的“对象”或“实例”,从而使用该类。在对变量的所有引用都超出范围之前,该变量始终保持在内存中。所有引用都超出范围时,CLR 将标记该变量以供垃圾回收。如果类声明为静态类,则内存中只存在一个副本,并且客户端代码只能通过该类自身而不是“实例变量”访问该类。
声明类
类使用 class 关键字进行声明,如下面的示例所示:

public class Customer
{
  //Fields, properties, methods and events go here...
}

class 关键字前面是访问级别。由于在该例中使用 public,因此任何人都可以基于该类创建对象。类的名称位于 class 关键字的后面。定义的其余部分是类的主体,用于定义行为和数据。类的字段、属性、方法和事件统称为“类成员”。
创建对象
尽管有时类和对象可互换,但它们是不同的概念。类定义对象的类型,但它不是对象本身。对象是基于类的具体实体,有时称为类的实例。
通过使用 new 关键字(后跟对象将基于的类的名称)可以创建对象,如下所示:

Customer object1 = new Customer();

创建类的实例后,将向程序员传递回对该对象的引用。在前面的示例中,object1 是对基于 Customer 的对象的引用。此引用引用新对象,但不包含对象数据本身。实际上,可以在根本不创建对象的情况下创建对象引用:

Customer object2;

建议不要创建像这样的不引用对象的对象引用,因为在运行时通过这样的引用来访问对象的尝试将会失败。但是,可以创建这样的引用来引用对象,方法是创建新对象,或者将它分配给现有的对象,如下所示:

Customer object3 = new Customer();
Customer object4 = object3;

此代码创建了两个对象引用,它们引用同一个对象。因此,通过 object3 对对象所做的任何更改都将反映在随后使用的 object4 中。由于基于类的对象是按引用来引用的,因此类称为引用类型。
类继承
继承是通过使用“派生”来实现的,而派生意味着类是使用“基类”声明的,它的数据和行为从基类继承。通过在派生的类名后面追加冒号和基类名称,可以指定基类,如下所示:

public class Manager : Employee
{
  // Employee fields, properties, methods and events are inherited
  // New Manager fields, properties, methods and events go here...
}

当类声明基类时,它继承基类除构造函数以外的所有成员。
与 C++ 不同,C# 中的类只能直接从一个基类继承。但是,因为基类自身也可能继承自另一个类,所以类可以间接继承多个基类。而且,一个类可以直接实现一个以上的接口。
类可以声明为抽象类。抽象类包含具有签名定义但没有实现的抽象方法。抽象类不能进行实例化。只能通过实现抽象方法的派生类使用抽象类。相比之下,密封类不允许其他类从其派生。
类定义可在不同的源文件之间进行拆分。
描述
下面的示例中定义了一个公共类,其中包含一个字段、一个方法和一个称为构造函数的特殊方法。有关更多信息,请参见构造函数(C# 编程指南)。然后使用 new 关键字将该类实例化。

public class Person
{
  // Field
  public string name;

  // Constructor that takes no arguments.
  public Person()
  {
    name = "unknown";
  }

  // Constructor that takes one argument.
  public Person(string nm)
  {
    name = nm;
  }

  // Method
  public void SetName(string newName)
  {
    name = newName;
  }
}
class TestPerson
{
  static void Main()
  {
    // Call the constructor that has no parameters.
    Person person1 = new Person();
    Console.WriteLine(person1.name);

    person1.SetName("John Smith");
    Console.WriteLine(person1.name);

    // Call the constructor that has one parameter.
    Person person2 = new Person("Sarah Jones");
    Console.WriteLine(person2.name);

    // Keep the console window open in debug mode.
    Console.WriteLine("Press any key to exit.");
    Console.ReadKey();
  }
}

输出:

unknown
John Smith
Sarah Jones

对象
类或结构定义的作用类似于蓝图,指定该类型可以进行哪些操作。从本质上说,对象是按照此蓝图分配和配置的内存块。程序可以创建同一个类的多个对象。对象也称为实例,可以存储在命名变量中,也可以存储在数组或集合中。使用这些变量来调用对象方法及访问对象公共属性的代码称为客户端代码。在 C# 等面向对象的语言中,典型的程序由动态交互的多个对象组成。

结构实例。. 选件类实例
由于类是引用类型,因此类对象的变量引用该对象在托管堆上的地址。如果将同一类型的第二个对象分配给第一个对象,则两个变量都引用该地址的对象。这一点将在本主题后面部分进行更详细的讨论。
类的实例是使用 new 运算符创建的。在下面的示例中,Person 为类型,person1 和 person 2 为该类型的实例(即对象)。

public class Person
{
  public string Name { get; set; }
  public int Age { get; set; }
  public Person(string name, int age)
  {
    Name = name;
    Age = age;
  }
  //Other properties, methods, events...
}

class Program
{
  static void Main()
  {
    Person person1 = new Person("Leopold", 6);
    Console.WriteLine("person1 Name = {0} Age = {1}", person1.Name, person1.Age);

    // Declare new person, assign person1 to it.
    Person person2 = person1;

    //Change the name of person2, and person1 also changes.
    person2.Name = "Molly";
    person2.Age = 16;

    Console.WriteLine("person2 Name = {0} Age = {1}", person2.Name, person2.Age);
    Console.WriteLine("person1 Name = {0} Age = {1}", person1.Name, person1.Age);

    // Keep the console open in debug mode.
    Console.WriteLine("Press any key to exit.");
    Console.ReadKey();

  }
}

输出:

  person1 Name = Leopold Age = 6
  person2 Name = Molly Age = 16
  person1 Name = Molly Age = 16

由于结构是值类型,因此结构对象的变量具有整个对象的副本。结构的实例也可以使用 new 运算符来创建,但这不是必需的,如下面的示例所示:

public struct Person
{
  public string Name;
  public int Age;
  public Person(string name, int age)
  {
    Name = name;
    Age = age;
  }
}

public class Application
{
  static void Main()
  {
    // Create struct instance and initialize by using "new".
    // Memory is allocated on thread stack.
    Person p1 = new Person("Alex", 9);
    Console.WriteLine("p1 Name = {0} Age = {1}", p1.Name, p1.Age);

    // Create new struct object. Note that struct can be initialized
    // without using "new".
    Person p2 = p1;

    // Assign values to p2 members.
    p2.Name = "Spencer";
    p2.Age = 7;
    Console.WriteLine("p2 Name = {0} Age = {1}", p2.Name, p2.Age);

    // p1 values remain unchanged because p2 is copy.
    Console.WriteLine("p1 Name = {0} Age = {1}", p1.Name, p1.Age);

    // Keep the console open in debug mode.
    Console.WriteLine("Press any key to exit.");
    Console.ReadKey();
  }
}

输出:

  p1 Name = Alex Age = 9
  p2 Name = Spencer Age = 7
  p1 Name = Alex Age = 9

p1 和 p2 的内存在线程堆栈上进行分配。该内存随声明它的类型或方法一起回收。这就是在赋值时复制结构的一个原因。相比之下,当对类实例对象的所有引用都超出范围时,为该类实例分配的内存将由公共语言运行时自动回收(垃圾回收)。无法像在 C++ 中那样明确地销毁类对象。

对象标识与. 值相等性
在比较两个对象是否相等时,首先必须明确您是想知道两个变量是否表示内存中的同一对象,还是想知道这两个对象的一个或多个字段的值是否相等。如果您要对值进行比较,则必须考虑这两个对象是值类型(结构)的实例,还是引用类型(类、委托、数组)的实例。
若要确定两个类实例是否引用内存中的同一位置(意味着它们具有相同的标识),可使用静态 Equals 方法。(System.Object 是所有值类型和引用类型的隐式基类,其中包括用户定义的结构和类。)
若要确定两个结构实例中的实例字段是否具有相同的值,可使用 ValueType.Equals 方法。由于所有结构都隐式继承自 System.ValueType,因此可以直接在对象上调用该方法,如下面的示例所示:

// Person is defined in the previous example.

//public struct Person
//{
//  public string Name;
//  public int Age;
//  public Person(string name, int age)
//  {
//    Name = name;
//    Age = age;
//  }
//}

Person p1 = new Person("Wallace", 75);
Person p2;
p2.Name = "Wallace";
p2.Age = 75;

if (p2.Equals(p1))
  Console.WriteLine("p2 and p1 have the same values.");

输出:

 p2 and p1 have the same values.

Equals 的 System.ValueType 实现使用反射,因为它必须能够确定任何结构中有哪些字段。在创建您自己的结构时,重写 Equals 方法可以提供针对您的类型的高效求等算法。

[!--infotagslink--]

相关文章

  • C#实现简单的登录界面

    我们在使用C#做项目的时候,基本上都需要制作登录界面,那么今天我们就来一步步看看,如果简单的实现登录界面呢,本文给出2个例子,由简入难,希望大家能够喜欢。...2020-06-25
  • 浅谈C# 字段和属性

    这篇文章主要介绍了C# 字段和属性的的相关资料,文中示例代码非常详细,供大家参考和学习,感兴趣的朋友可以了解下...2020-11-03
  • php svn操作类

    以前我们开发大型项目时都会用到svn来同步,因为开发产品的人过多,所以我们会利用软件来管理,今天发有一居然可以利用php来管理svn哦,好了看看吧。 代码如下 ...2016-11-25
  • PHP 数据库缓存Memcache操作类

    操作类就是把一些常用的一系列的数据库或相关操作写在一个类中,这样调用时我们只要调用类文件,如果要执行相关操作就直接调用类文件中的方法函数就可以实现了,下面整理了...2016-11-25
  • java8如何用Stream查List对象某属性是否有重复

    这篇文章主要介绍了java8如何用Stream查List对象某属性是否有重复的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-11
  • C#中截取字符串的的基本方法详解

    这篇文章主要介绍了C#中截取字符串的的基本方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-03
  • C#连接SQL数据库和查询数据功能的操作技巧

    本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
  • C#实现简单的Http请求实例

    这篇文章主要介绍了C#实现简单的Http请求的方法,以实例形式较为详细的分析了C#实现Http请求的具体方法,需要的朋友可以参考下...2020-06-25
  • C#中new的几种用法详解

    本文主要介绍了C#中new的几种用法,具有很好的参考价值,下面跟着小编一起来看下吧...2020-06-25
  • 使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序)

    这篇文章主要介绍了使用Visual Studio2019创建C#项目(窗体应用程序、控制台应用程序、Web应用程序),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2020-06-25
  • C#开发Windows窗体应用程序的简单操作步骤

    这篇文章主要介绍了C#开发Windows窗体应用程序的简单操作步骤,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-04-12
  • C#从数据库读取图片并保存的两种方法

    这篇文章主要介绍了C#从数据库读取图片并保存的方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2021-01-16
  • C#和JavaScript实现交互的方法

    最近做一个小项目不可避免的需要前端脚本与后台进行交互。由于是在asp.net中实现,故问题演化成asp.net中jiavascript与后台c#如何进行交互。...2020-06-25
  • 经典实例讲解C#递归算法

    这篇文章主要用实例讲解C#递归算法的概念以及用法,文中代码非常详细,帮助大家更好的参考和学习,感兴趣的朋友可以了解下...2020-06-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • 轻松学习C#的基础入门

    轻松学习C#的基础入门,了解C#最基本的知识点,C#是一种简洁的,类型安全的一种完全面向对象的开发语言,是Microsoft专门基于.NET Framework平台开发的而量身定做的高级程序设计语言,需要的朋友可以参考下...2020-06-25
  • C#变量命名规则小结

    本文主要介绍了C#变量命名规则小结,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-09
  • c#中(&&,||)与(&,|)的区别详解

    这篇文章主要介绍了c#中(&&,||)与(&,|)的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-06-25
  • C# 中如何取绝对值函数

    本文主要介绍了C# 中取绝对值的函数。具有很好的参考价值。下面跟着小编一起来看下吧...2020-06-25
  • C#绘制曲线图的方法

    这篇文章主要介绍了C#绘制曲线图的方法,以完整实例形式较为详细的分析了C#进行曲线绘制的具体步骤与相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25