C#基础—类2

前言:

类是引用类型。 创建类的对象后,向其分配对象的变量仅保留对相应内存的引用。 将对象引用分配给新变量后,新变量会引用原始对象。 通过一个变量所做的更改将反映在另一个变量中,因为它们引用相同的数据。

结构是值类型。 创建结构时,向其分配结构的变量保留结构的实际数据。 将结构分配给新变量时,会复制结构。 因此,新变量和原始变量包含相同数据的副本(共两个)。 对一个副本所做的更改不会影响另一个副本。

一般来说,类用于对更复杂的行为或应在类对象创建后进行修改的数据建模。 结构最适用于所含大部分数据不得在结构创建后进行修改的小型数据结构。

类属于构造,使用类,可以通过组合其他类型的变量、方法和事件创建自己的自定义类型。 类好比是蓝图。 它定义类型的数据和行为。

如果类未声明为静态,客户端代码就可以通过创建分配给变量的对象或实例来使用该类。 变量会一直保留在内存中,直至对变量的所有引用超出范围为止。 超出范围时,CLR 将对其进行标记,以便用于垃圾回收。

如果类声明为静态,则内存中只有一个副本,且客户端代码只能通过类本身,而不是实例变量来访问它。

访问修饰符在进行声明时指定类型或成员的可访问性:

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

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

受保护
只有同一类或者从该类派生的类中的代码可以访问该类型或成员。
内部
同一程序集中的任何代码都可以访问该类型或成员,但其他程序集中的代码不可以。

受保护的内部 该类型或成员可由对其进行声明的程序集或另一程序集中的派生类中的任何代码访问。

专用受保护只有在其声明程序集内,通过相同类中的代码或派生自该类的类型,才能访问类型或成员。

1.封装

封装有时称为面向对象的编程的第一支柱或原则。 根据封装原则,类或结构可以指定自己的每个成员对外部代码的可访问性。 可以隐藏不得在类或程序集外部使用的方法和变量,以限制编码错误或恶意攻击发生的可能性。

2.继承

类(而非结构)支持继承的概念。 派生自另一个类(基类)的类自动包含基类的所有公共、受保护和内部成员(其构造函数和终结器除外)。 -----类声明基类时,会继承基类除构造函数外的所有成员。

可以将类声明为 abstract,即一个或多个方法没有实现代码。 尽管抽象类无法直接实例化,但可以作为提供缺少实现代码的其他类的基类。 类还可以声明为 sealed,以阻止其他类继承。

3.多态

多态性常被视为自封装和继承之后,面向对象的编程的第三个支柱。 Polymorphism(多态性)是一个希腊词,指“多种形态”,多态性具有两个截然不同的方面:

  • 在运行时,在方法参数和集合或数组等位置,派生类的对象可以作为基类的对象处理。 发生此情况时,该对象的声明类型不再与运行时类型相同。

  • 基类可以定义并实现方法,派生类可以重写这些方法,即派生类提供自己的定义和实现。 在运行时,客户端代码调用该方法,CLR 查找对象的运行时类型,并调用虚方法的重写方法。 因此,你可以在源代码中调用基类的方法,但执行该方法的派生类版本。

4.接口

类和结构可以继承多个接口。 继承自接口意味着类型实现接口中定义的所有方法。

5.静态类型及类成员

类(而非结构)可以声明为 static静态类只能包含静态成员,不能使用新的关键字进行实例化。 在程序加载时,类的一个副本会加载到内存中,而其成员则可通过类名进行访问。 类和结构都能包含静态成员。

由于不存在任何实例变量,因此可以使用类名本身访问静态类的成员。

静态类可以用作只对输入参数进行操作并且不必获取或设置任何内部实例字段的方法集的方便容器。例如,在 .NET Framework 类库中,静态 System.Math 类包含执行数学运算,而无需存储或检索对 Math 类特定实例唯一的数据的方法。

与所有类类型的情况一样,静态类的类型信息在引用该类的程序加载时,由 .NET Framework 公共语言运行时 (CLR) 加载。 程序无法确切指定类加载的时间。 但是,可保证进行加载,以及在程序中首次引用类之前初始化其字段并调用其静态构造函数。 静态构造函数只调用一次,在程序所驻留的应用程序域的生存期内,静态类会保留在内存中。

  • 只包含静态成员,若要访问静态类成员,请使用类的名称指定成员的位置

  • 无法进行实例化

  • 会进行密封,因此不能继承

  • 不能包含实例构造函数,静态构造函数只调用一次

静态成员

非静态类可以包含静态方法、字段、属性或事件。 即使未创建类的任何实例,也可对类调用静态成员。 静态成员始终按类名(而不是实例名称)进行访问。 静态成员只有一个副本存在(与创建的类的实例数有关,应该是无关)。 静态方法和属性无法在其包含类型中访问非静态字段和事件,它们无法访问任何对象的实例变量,除非在方法参数中显式传递它。

更典型的做法是声明具有一些静态成员的非静态类(而不是将整个类都声明为静态)。 静态字段的两个常见用途是保留已实例化的对象数的计数,或是存储必须在所有实例间共享的值。

静态方法可以进行重载,但不能进行替代,因为它们属于类,而不属于类的任何实例。

虽然字段不能声明为 static const,不过 const 字段在其行为方面本质上是静态的。 它属于类型,而不属于类型的实例。 因此,可以使用用于静态字段的相同 ClassName.MemberName 表示法来访问常量字段。 无需进行对象实例化。

C# 不支持静态局部变量(在方法范围中声明的变量)。

public class Automobile
{
    public static int NumberOfWheels = 4;
    public static int SizeOfGasTank
    {
        get
        {
            return 15;
        }
    }
    public static void Drive() { }
    public static event EventType RunOutOfGas;

    // Other non-static fields and properties...
}

6.抽象类、密封类及类成员

使用 abstract 关键字可以创建不完整且必须在派生类中实现的类和 class 成员。

使用 sealed 关键字可以防止继承以前标记为 virtual 的类或某些类成员。

I.抽象类和类成员 

通过在类定义前面放置关键字 abstract,可以将类声明为抽象类。 例如:

public abstract class A
{
    // Class members here.
}

抽象类不能实例化。 抽象类的用途是提供一个可供多个派生类共享的通用基类定义。抽象类也可以定义抽象方法。 方法是将关键字 abstract 添加到方法的返回类型的前面。 例如:

public abstract class A
{
    public abstract void DoWork(int i);
}

抽象方法没有实现,所以方法定义后面是分号,而不是常规的方法块。 抽象类的派生类必须实现所有抽象方法。 当抽象类从基类继承虚方法时,抽象类可以使用抽象方法重写该虚方法。 例如:

// compile with: /target:library
public class D
{
    public virtual void DoWork(int i)
    {
        // Original implementation.
    }
}

public abstract class E : D
{
    public abstract override void DoWork(int i);
}

public class F : E
{
    public override void DoWork(int i)
    {
        // New implementation.
    }
}

如果 virtual 方法声明为 abstract,则该方法对于从抽象类继承的所有类而言仍然是虚方法。 继承抽象方法的类无法访问方法的原始实现,因此在上一示例中,类 F 上的 DoWork 无法调用类 D 上的 DoWork

通过这种方式,抽象类可强制派生类向虚拟方法提供新的方法实现

II.密封类和类成员 

通过在类定义前面放置关键字 sealed,可以将类声明为密封类例如:

public sealed class D
{
    // Class members here.
}

密封类不能用作基类。 因此,它也不能是抽象类。 密封类禁止派生。 由于密封类从不用作基类,所以有些运行时优化可以略微提高密封类成员的调用速度。

在对基类的虚成员进行重写的派生类上,方法、索引器、属性或事件可以将该成员声明为密封成员。 在用于以后的派生类时,这将取消成员的虚效果。 方法是在类成员声明中将 sealed 关键字置于 override 关键字前面。 例如:

public class D : C
{
    public sealed override void DoWork() { }
}
余生很长,愿我们都活成自己喜欢的样子
原文地址:https://www.cnblogs.com/bananana/p/8710320.html