面向对象的编程(C# 和 Visual Basic)

.NET Framework 中的所有托管语言(例如 Visual Basic 和 C#)都全面支持面向对象的编程,包括封装、继承和多态性。

“封装”意味着将一组相关属性、方法和其他成员视为一个单元或对象。

“继承”描述基于现有类创建新类的能力。

“多态性”意味着可以有多个可互换使用的类,即使每个类以不同方式实现相同属性或方法。

本节介绍下列概念:

  • 类和对象

    • 类成员

      属性和字段

      方法

      构造函数

      析构函数

      事件

      嵌套类

    • 访问修饰符和访问级别

    • 实例化类

    • 静态(共享)类和成员

    • 匿名类型

  • 继承

    • 重写成员
  • 接口

  • 泛型

  • 委托

类和对象

“类”和“对象”这两个术语有时互换使用,但实际上,类描述对象的“类型”,而对象是类的可用“实例”。 因此,创建对象的操作称为“实例化”。 如果使用蓝图类比,类是蓝图,对象就是基于该蓝图的建筑。

定义类:

Class SampleClass
End Class
class SampleClass
{
}

Visual Basic 和 C# 还提供了类的轻量版本,称为“结构”。当需要创建大量对象但不希望因此占用太多内存时,可以使用此轻量版本。

定义结构:

Structure SampleStructure
End Structure
struct SampleStruct
{
}

有关更多信息,请参见:

类成员

每个类都可以具有不同的“类成员”。类成员包括属性(用于描述类数据)、方法(用于定义类行为)和事件(用于在不同的类和对象之间提供通信)。

属性和字段

字段和属性表示对象包含的信息。 字段类似于变量,因为可以直接读取或设置它们。

定义字段:

Class SampleClass
    Public SampleField As String
End Class
Class SampleClass
{
    public string sampleField;
}

属性具有 get 和 set 过程,它们对如何设置或返回值提供更多的控制。

C# 和 Visual Basic 都允许您创建私有字段来存储属性值,或者使用常说的“自动实现的属性”,这些属性自动在后台创建此字段,并为属性过程提供基本逻辑。

定义自动实现的属性:

Class SampleClass
    Public Property SampleProperty as String
End Class
class SampleClass
{
    public int SampleProperty { get; set; }
}

如果您需要执行一些其他操作来读取和写入属性值,请定义一个用于存储属性值的字段,并提供用于存储和检索该字段的基本逻辑:

Class Samplelass
    Private m_Sample As String
    Public Property Sample() As String
        Get
            ' Return the value stored in the field.
            Return m_Sample
        End Get
        Set(ByVal Value As String)
            ' Store the value in the field.
            m_Sample = Value
        End Set
    End Property
End Class
class SampleClass
{
    private int _sample;
    public int Sample
    {
        // Return the value stored in a field.
        get { return _sample; }
        // Store the value in the field.
        set { _sample = value; }
    }
}

大多数属性的方法或过程都是既可以设置也可以获取属性值。 但您可以创建只读或只写属性来限制对它们的修改或读取。 在 Visual Basic 中,可以使用 ReadOnly 和 WriteOnly 关键字。 在 C# 中,可以忽略 get 或 set 属性方法。 但在 Visual Basic 和 C# 中,自动实现的属性都不能为只读或只写。

有关更多信息,请参见:

方法

“方法”是对象可以执行的操作。

提示

在 Visual Basic 中,方法的创建途径有两种:如果方法不返回值,可使用 Sub 语句;如果方法返回值,可使用 Function 语句。

定义类的方法:

Class SampleClass
    Public Function SampleFunc(ByVal SampleParam As String)
        ' Add code here
    End Function
End Class
class SampleClass
{
    public int sampleMethod(string sampleParam)
    {
        // Insert code here
    }
}

对于同一方法,一个类可以有多个实现,也叫“重载”,这些实现的区别在于参数个数或参数类型的不同。

重载方法:

Overloads Sub Display(ByVal theChar As Char)
    ' Add code that displays Char data.
End Sub
Overloads Sub Display(ByVal theInteger As Integer)
    ' Add code that displays Integer data.
End Sub
public int sampleMethod(string sampleParam) {};
public int sampleMethod(int sampleParam) {}

大多数情况下,方法是在类定义中声明的。 但 Visual Basic 和 C# 都还支持“扩展方法”,这种方法允许您将方法添加到实际类定义之外的现有类中。

有关更多信息,请参见:

构造函数

构造函数一种类方法,它们在创建给定类型的对象时自动执行。 构造函数通常用于初始化新对象的数据成员。 构造函数只能在创建类时运行一次。 此外,构造函数中的代码始终在类中所有其他代码之前运行。 但是,您可以按照为任何其他方法创建重载的方式,创建多个构造函数重载。

定义类的构造函数:

Class SampleClass
    Sub New(ByVal s As String)
        // Add code here.
    End Sub
End Class
public class SampleClass
{
    public SampleClass()
    {
        // Add code here
    }
}

有关更多信息,请参见:

析构函数

析构函数用于析构类的实例。 在 .NET Framework 中,垃圾回收器自动管理应用程序中托管对象的内存分配和释放。 但是,您可能仍会需要析构函数来清理应用程序创建的所有非托管资源。 一个类只能有一个析构函数。

有关析构函数和 .NET Framework 垃圾回收的更多信息,请参见垃圾回收

事件

类或对象可以通过事件向其他类或对象通知发生的相关事情。 发送(或引发)事件的类称为“发行者”,接收(或处理)事件的类称为“订阅方”。 有关事件以及如何引发和处理事件的更多信息,请参见处理和引发事件

嵌套类

在另一个类中定义的类称为“嵌套”。 默认情况下,嵌套类是私有类。

Class Container
    Class Nested
    ' Add code here.
    End Class
End Class
class Container
{
    class Nested
    {
        // Add code here.
    }
}

若要创建嵌套类的实例,请使用容器类的名称,后接一个点,再接嵌套类的名称:

Dim nestedInstance As Container.Nested = New Container.Nested()
Container.Nested nestedInstance = new Container.Nested()

访问修饰符和访问级别

所有类和类方法都可以使用“访问修饰符”指定自己为其他类提供的访问级别。

可用的访问修饰符有以下这些:

Visual Basic 修饰符

C# 修饰符

定义

Public (Visual Basic)

public

同一程序集中的任何其他代码或引用该程序集的其他程序集都可以访问该类型或成员。

Private (Visual Basic)

private

只有同一类中的代码可以访问该类型或成员。

Protected (Visual Basic)

protected

只有同一类或派生类中的代码可以访问该类型或成员。

Friend (Visual Basic)

internal

同一程序集中的任何代码都可以访问该类型或成员,但其他程序集中的代码不可以。

Protected Friend

protected internal

同一程序集中的任何代码或其他程序集中的任何派生类都可以访问该类型或成员。

有关更多信息,请参见 Visual Basic 中的访问级别访问修饰符(C# 编程指南)

实例化类

若要创建对象,您需要实例化类,即创建类实例。

Dim sampleObject as New SampleClass()
SampleClass sampleObject = new SampleClass();

实例化类之后,可以为该实例的属性和字段赋值,还可以调用类方法。

' Set a property value.
sampleObject.SampleProperty = "Sample String"
' Call a method.
sampleObject.SampleMethod()
// Set a property value.
sampleObject.sampleProperty = "Sample String";
// Call a method.
sampleObject.sampleMethod();

若要在类的实例化过程中为属性赋值,请使用对象初始值设定项:

Dim sampleObject = New SampleClass With 
    {.FirstProperty = "A", .SecondProperty = "B"}
// Set a property value.
SampleClass sampleObject = new SampleClass 
    { FirstProperty = "A", SecondProperty = "B" };

有关更多信息,请参见:

静态(共享)类和成员

类的静态(在 Visual Basic 中为共享)成员是指由该类的所有实例共享的属性、过程或字段。

定义静态(共享)成员:

Class SampleClass
    Public Shared SampleString As String = "Sample String"
End Class
static class SampleClass
{
    public static string SampleString = "Sample String";
}

若要访问静态(共享)成员,请使用类的名称,但不要创建此类的对象:

MsgBox(SampleClass.SampleString)
Console.WriteLine(SampleClass.SampleString);

C# 中的静态类和 Visual Basic 中的共享模块只有静态(共享)成员,无法进行实例化。 相应地,静态(共享)成员无法访问非静态(非共享)属性、字段或方法。

有关更多信息,请参见:

匿名类型

匿名类型使您无需为数据类型编写类定义即可创建对象。 此时,编译器将为您生成类。 该类没有可使用的名称,且包含在声明对象时指定的属性。

创建匿名类型的实例:

' sampleObject is an instance of a simple anonymous type.
Dim sampleObject = 
    New With {Key .FirstProperty = "A", .SecondProperty = "B"}
// sampleObject is an instance of a simple anonymous type.
var sampleObject = 
    new { FirstProperty = "A", SecondProperty = "B" };

有关更多信息,请参见:

继承

通过继承,可以创建一个新类,它重用、扩展和修改另一个类中定义的行为。 其成员被继承的类称为“基类”,继承这些成员的类称为“派生类”。 但是,C# 和 Visual Basic 中的所有类都隐式继承自 Object 类,该类支持 .NET 类层次结构,并为所有类提供低级别服务。

提示

.NET Framework 中的托管语言不支持多重继承,即, 只能为一个派生类指定一个基类。

从基类继承:

Class DerivedClass
    Inherits BaseClass
End Class
class DerivedClass:BaseClass{}

默认情况下,可以继承所有类。 但您可以指定不得将某个类用作基类,也可以创建只能用作基类的类。

指定不得将某个类用作基类:

NotInheritable Class SampleClass
End Class
public sealed class A { }

指定只能用作基类且无法实例化的类:

MustInherit Class BaseClass
End Class
public abstract class B { }

有关更多信息,请参见:

重写成员

默认情况下,派生类继承其基类的所有成员。 若希望更改继承成员的行为,则需要重写该成员。 即,可以在派生类中定义方法、属性或事件的新实现。

下列修饰符用于控制如何重写属性和方法:

Visual Basic 修饰符

C# 修饰符

定义

Overridable (Visual Basic)

virtual(C# 参考)

允许在派生类中重写类成员。

Overrides (Visual Basic)

override(C# 参考)

重写基类中定义的虚拟(可重写)成员。

NotOverridable (Visual Basic)

不支持

禁止在继承类中重写成员。

MustOverride (Visual Basic)

abstract(C# 参考)

要求在派生类中重写类成员。

Shadows (Visual Basic)

new 修饰符(C# 参考)

隐藏继承自基类的成员

接口

和类一样,接口也定义了一系列属性、方法和事件。 但与类不同的是,接口并不提供实现。 它们由类来实现,并从类中被定义为单独的实体。 接口表示一种约定,实现接口的类必须严格按其定义来实现接口的每个方面。

定义接口:

Public Interface ISampleInterface
    Sub DoSomething()
End Interface
interface ISampleInterface
{
    void doSomething();
}

在类中实现接口:

Class SampleClass
    Implements ISampleInterface
    Sub doSomething
        ' Method implementation.
    End Sub
End Class
class SampleClass : ISampleInterface
{
    void ISampleInterface.SampleMethod()
    {
        // Method implementation.
    }
}

有关更多信息,请参见:

泛型

.NET Framework 中的类、结构、接口和方法可以是“类型参数”,类型参数定义它们可以存储或使用的对象的类型。 最常见的泛型示例是集合,从中可以指定要存储在集合中的对象的类型。

定义泛型类:

Class SampleGeneric(Of T)
    Public Field As T
End Class
Public class SampleGeneric<T> 
{
    public T Field;
}

创建泛型类的实例:

Dim sampleObject As New SampleGeneric(Of String)
sampleObject.Field = "Sample string"
SampleGeneric<string> sampleObject = new SampleGeneric<string>();
sampleObject.Field = "Sample string";

有关更多信息,请参见:

委托

“委托”是一种类型,它定义方法签名,可以提供对具有兼容签名的任何方法的引用。 您可以通过委托调用方法。 委托用于将方法作为参数传递给其他方法。

提示

事件处理程序就是通过委托调用的方法。 有关在事件处理中使用委托的更多信息,请参见事件和委托

创建委托:

Delegate Sub SampleDelegate(ByVal str As String)
public delegate void SampleDelegate(string str);

创建对与委托指定的签名相匹配的方法的引用:

Class SampleClass
    ' Method that matches the SampleDelegate signature.
    Sub SampleSub(ByVal str As String)
        ' Add code here.
    End Sub
    ' Method that instantiates the delegate.
    Sub SampleDelegateSub()
        Dim sd As SampleDelegate = AddressOf SampleSub
        sd("Sample string")
    End Sub
End Class
class SampleClass
{
    // Method that matches the SampleDelegate signature.
    public static void sampleMethod(string message)
    {
        // Add code here.
    }
    // Method that instantiates the delegate.
    void SampleDelegate()
    {
        SampleDelegate sd = sampleMethod;
        sd("Sample string");
    }
}

有关更多信息,请参见:

请参见

概念

C# 编程指南

其他资源

Visual Basic 编程指南