学习C语言的类和对象

228 阅读10分钟

在本教程中,我们将讨论C#编程语言中的类和对象。类的意义是什么,它们的用途是什么?在面向对象的编程中,创建类的目的是为了让程序员有能力在软件中模拟或接近真实世界。有主张OOP风格的人,也有反对OOP的人。在本教程中,我们不会为一种编程风格与另一种风格作担保,而是研究如何在C#中创建类,以面向对象的风格进行编程。


几个类文件一起工作

在我们刚刚完成的C#介绍中,我们只处理了一个文件,即Program.cs。当我们开始使用C#中的类和对象时,驱动应用程序的代码将被分割成多个文件。我们将创建一个小程序,跟踪股票价格的集合,并输出关于这些价格的一些计算结果。

我们可以通过在Visual Studio中创建一个新项目来开始。我将选择文件->新建->项目,然后选择一个Visual C#控制台应用程序,并提供一个名称为Stocks。
new visual studio console app

Visual Studio现在为我们创建了一个新的项目,并创建了一个Stocks的命名空间和第一个类,即Program。这个类包含了应用程序的入口点,即Main方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Stocks
{
    class Program
    {
        static void Main(string[] args)
        {
        }
    }
}

添加一个股票组合

我们可以添加一个新的类,可以在程序的Main方法中使用,但是我们在哪里以及如何创建一个新的类?按照惯例,许多C#程序员会为每个将要使用的创建一个新文件。你可以把所有你利用的类放在一个文件中,但这并不是一个最佳做法。为了给我们的项目添加一个新的类,我们可以右击项目名称,然后选择添加,再选择类。
add class to visual studio project

在新类对话框中,我们给出文件名StockPortfolio.cs,然后点击添加。
name new class file in visual studio

这将创建一个与类同名的新文件,并为我们搭建出以下模板代码。
StockPortfolio.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Stocks
{
    class StockPortfolio
    {
    }
}

类的定义中使用了 **class**关键字,后面是类的名称。这些大括号之间的任何代码现在都属于这个类。StockPortfolio是Stocks命名空间中的一个成员。


两种类型的成员

通常情况下,一个类中有两种成员。第一种是用于保存数据或状态。这些是类中的属性或变量。StockPortfolio类的状态是为一只股票输入的价格。

我们还需要一个可以处理行为或行动者的类的成员。这些方法可以为我们做工作。这些方法可以与StockPortfolio进行交互,并做一些事情,如添加股票价格或计算股票价格的统计数据。类的名称通常是一个名词,而为该类做工作的方法是动词。

我们可以先添加一个方法,让我们把股票价格添加到StockPortfolio中。我们将它称为 AddStock().当这个方法被调用时,任何在相关大括号之间的代码都将被执行。它接受一个float类型的参数,这个参数被命名为股票。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Stocks
{
    class StockPortfolio
    {
        public void AddStock(float stock)
        {
            
        }
    }
}

现在我们需要一种方法来存储这种状态。为此,我们可以使用C# List,它指的是一个强类型的列表,可以通过索引访问。List提供了可用的方法来搜索、排序和操作所包含的数据。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Stocks
{
    class StockPortfolio
    {
        public void AddStock(float stock)
        {
            stocks.Add(stock);
        }

        private List<float> stocks = new List<float>();
    }
}

到目前为止,我们的项目中有两个类:ProgramStockPortfolio。这两个类都有自己的文件,以 .cs扩展。


用我们的类创建新对象

现在我们已经创建了一个可以做事的类,我们可以创建一个新的对象来实际使用这些代码。在Program.cs文件的主方法中,我们现在可以 "新建 "一个StockPortfolio类型的对象,并将其存储在一个变量中。然后,该变量可以引用我们创建的方法--AddStock。因此,下面我们创建了一个新的对象,然后向该对象添加6个不同的股票价格。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Stocks
{
    class Program
    {
        static void Main(string[] args)
        {
            StockPortfolio portfolio = new StockPortfolio();

            portfolio.AddStock(10);
            portfolio.AddStock(25);
            portfolio.AddStock(85);
            portfolio.AddStock(220);
            portfolio.AddStock(7);
            portfolio.AddStock(117);
            portfolio.AddStock(117);
        }
    }
}

到目前为止,我们的程序并没有做很多事情,但是如果我们建立解决方案,设置一个断点,然后开始调试--我们可以看到这个类正在工作。它已经将6种股票价格添加到对象中,调试器也向我们显示了这一点。
Visual Studio Start Debugging Example


C# 构造函数

什么是构造函数,它的用途是什么?在C#中,我们可以使用 **new**关键字来从一个类中创建一个对象。这也被称为实例化类,并将触发一个被称为构造函数的特殊方法,以帮助建立对象。所有的类都有一个默认的构造函数,在C#中隐性存在。

然而,你可能想创建你自己的构造函数来覆盖默认的构造函数。这对于对对象的初始化有更多的控制是很方便的。通过这种方法,你可以为对象初始化字段和数据,并设置默认值。在C#中定义你自己的构造函数与创建方法类似。你可以使用 **public**关键字,然后是类的名称,后面加括号。

现在让我们为我们的StockPortfolio类添加一个自定义构造函数。在其中,我们可以初始化股票变量。请注意,该方法的名称与类的名称相同,即StockPortfolio。这就是我们如何知道它是一个构造函数。我们不需要使用像PHP中的__construct那样的特殊关键字。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Stocks
{
    class StockPortfolio
    {
        public StockPortfolio()
        {
            stocks = new List<float>();
        }

        public void AddStock(float stock)
        {
            stocks.Add(stock);
        }

        private List<float> stocks;
    }
}

C#中的类和变量

在C#中,有类,也有变量,但这两者之间有什么区别?你可能以前听说过,一个类就像一个蓝图。然后你可以使用该蓝图来创建对象的实例。通过使用 new关键字与我们的类名相结合,我们就可以在内存中实例化一个该类型的对象。我们的StockPortfolio类可以容纳一个股票价格的列表。

C#的一个有趣的方面是,开发者可以用一个类来定义变量的类型。这是因为C#是强类型的,或者换句话说,每个变量都需要有一个类型。我们在上面写代码的时候看到了这一点。

StockPortfolio portfolio = new StockPortfolio();

这里的 **portfolio**变量的类型是StockPortfolio。当一个类被用来对一个变量进行类型化时,它是为了让开发者知道可以对一个对象做什么。在我们的例子中,我们将能够存储股票价格并对其进行一些简单的计算。


C#中的引用类型

在C#中,类是一种引用类型。如果一个数据是一个引用类型,它存储的是对数据的引用,而不是数据本身。引用类型是在上分配的。当你把一个引用类型的变量分配给一个不同的变量时,你是通过值传递的,不管你信不信。你向第二个变量传递了一个引用的副本。


C#访问修饰符

访问修饰符在面向对象编程中提供了封装和数据隐藏。三个最常见的访问修饰符是public、private和protected。还有内部、受保护的内部和受保护的私有,但这些并不经常使用。

  • public可以被同一类中的任何其他代码或引用它的其他类所访问。
  • private只能由同一类中的代码访问。
  • protected只能由同一类或派生类中的代码访问。

在我们的类中,我们有一个公共的构造函数,一个公共的AddStock()方法,以及一个私有的股票属性。
C# access modifiers


C#中的静态成员

在使用类时,我们几乎总是需要在做任何工作之前创建一个类的实例。换句话说,你需要使用 new关键字来调用一个构造函数并创建一个类的对象。如果我告诉你有一种方法可以在不需要初始化对象的情况下做一些工作呢?好吧,有一个这样的方法。它是通过使用一个静态成员。

一个类中的静态方法或属性是你可以在代码中访问的东西,而不需要先创建一个类的实例。例如,考虑当你使用C#中的Console.WriteLine()方法时。你不需要通过使用关键字来创建一个新的对象。 new关键字来创建一个新对象,以便使用该方法。为什么呢?因为WriteLine()是一个静态方法!

console writeline static method

这里可以看到Writeline的方法签名。

public static void WriteLine(string value);

添加一个新的类

下面突出显示的一行将允许我们计算一些关于我们已经添加到程序中的股票价格的统计数据。如果能够查看所有的价格并自动计算诸如平均股价、最高股价和最低股价,那就更好了。因此,有了这个新行,我们将需要更多的代码和一个新的类。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Stocks
{
    class Program
    {
        static void Main(string[] args)
        {
            StockPortfolio portfolio = new StockPortfolio();
            portfolio.AddStock(10);
            portfolio.AddStock(25);
            portfolio.AddStock(85);
            portfolio.AddStock(220);
            portfolio.AddStock(7);
            portfolio.AddStock(117);

            StockStatistics stats = portfolio.ComputeStatistics();
            
            Console.WriteLine("The average price is " + stats.AverageStock);
            Console.WriteLine("The highest price is " + stats.HighestStock);
            Console.WriteLine("The lowest price is " + stats.LowestStock);
        }
    }
}

首先,我们要像这样添加一个新的C#类文件。它将被命名为StockStatistics。
new c# class file

我们可以用一些代码来填充这个新类。注意我们是如何设置一个构造函数并初始化最高股价和最低股价的。此外,我们有三个属性可以用来保存数据。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Stocks
{
    class StockStatistics
    {
        public StockStatistics()
        {
            HighestStock = 0;
            LowestStock = float.MaxValue;
        }

        public float AverageStock;
        public float HighestStock;
        public float LowestStock;
    }
}

现在我们可以回到StockPortfolio.cs类文件,添加一个ComputeStatistics()公共方法,该方法属于StockStatistics类型。我们上面刚刚创建的代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Stocks
{
    class StockPortfolio
    {
        public StockPortfolio()
        {
            stocks = new List<float>();
        }

        public StockStatistics ComputeStatistics()
        {
            StockStatistics stats = new StockStatistics();


            float sum = 0;
            foreach (float stock in stocks)
            {
                stats.HighestStock = Math.Max(stock, stats.HighestStock);
                stats.LowestStock = Math.Min(stock, stats.LowestStock);
                sum += stock;
            }

            stats.AverageStock = sum / stocks.Count;
            return stats;
        }

        public void AddStock(float stock)
        {
            stocks.Add(stock);
        }

        private List<float> stocks;
    }
}

最后,让我们回到主Program.cs文件,重新审视Main()方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Stocks
{
    class Program
    {
        static void Main(string[] args)
        {
            StockPortfolio portfolio = new StockPortfolio();

            portfolio.AddStock(10);
            portfolio.AddStock(25);
            portfolio.AddStock(85);
            portfolio.AddStock(220);
            portfolio.AddStock(7);
            portfolio.AddStock(117);
            portfolio.AddStock(117);

            StockStatistics stats = portfolio.ComputeStatistics();

            Console.WriteLine("The average price is " + stats.AverageStock);
            Console.WriteLine("The highest price is " + stats.HighestStock);
            Console.WriteLine("The lowest price is " + stats.LowestStock);
        }
    }
}

当程序运行时,我们应该看到一些关于我们输入到程序中的股票价格的有趣输出。首先,我们必须像这样构建解决方案,创建一个程序集
vs studio build solution

我们可以通过选择 "不调试开始 "选项来运行该程序。
Visual Studio Start Without Debugging

如果你跟在后面,一切都很顺利,我们就会看到基于我们输入的所有价格的程序输出。


C#类和对象总结

关于C#语言中类和对象的一些特性的本教程到此结束。我们看到了如何定义一个类,以及如何在该类中定义一个构造函数。一个类的构造函数可以用来设置初始值,或者在第一次创建对象时执行一些基本任务。我们使用 **new**关键字和一个类的名字结合起来,从该类中创建一个新的对象。任何给定的类都可以有一个以上的实例。当然,在谈论面向对象的编程时,我们只需要介绍一下访问修改器,以及它们如何提供信息隐藏和封装。这些是 public, private,和 **protected**关键字。