目录
  • 一、类和对象
    • 1、类型参数
    • 2、基类
  • 二、结构
    • 三、接口
      • 四、枚举
        • 五、可为 null 的类型
          • 六、元组

            前言:

            作为面向对象的语言,C# 支持封装、继承和多态性这些概念。 类可能会直接继承一个父类,并且可以实现任意数量的接口。 若要用方法重写父类中的虚方法,必须使用 override 关键字,以免发生意外重定义。 在 C# 中,结构就像是轻量级类,是可以实现接口但不支持继承的堆栈分配类型。 C# 提供了 record class record struct 类型,这些类型的目的主要是存储数据值。

            一、类和对象

            类 是最基本的 C# 类型。 类是一种数据结构,可在一个单元中就将状态(字段)和操作(方法和其他函数成员)结合起来。 类为类实例(亦称为“对象”)提供了定义 。 类支持 继承 和 多形性,即 派生类 可以扩展和专门针对 基类 的机制。

            新类使用类声明进行创建。 类声明以标头开头。 标头指定以下内容:

            • 类的特性和修饰符
            • 类的名称
            • 基类(从基类继承时)
            • 接口由该类实现。

            标头后面是类主体,由在分隔符 { 和 } 内编写的成员声明列表组成。

            以下代码展示的是简单类 Point 的声明:

            public class Point
            {
                public int X { get; }
                public int Y { get; }
                
                public Point(int x, int y) => (X, Y) = (x, y);
            }
            
            
            

            类实例是使用 new 运算符进行创建,此运算符为新实例分配内存,调用构造函数来初始化实例,并返回对实例的引用。 以下语句创建两个 Point 对象,并将对这些对象的引用存储在两个变量中:

            var p1 = new Point(0, 0);
            var p2 = new Point(10, 20);
            
            
            

            当无法再访问对象时,对象占用的内存会被自动回收。 没有必要也无法在 C# 中显式解除分配对象。

            1、类型参数

            泛型类定义类型参数。 类型参数是用尖括号括起来的类型参数名称列表。 类型参数跟在类名后面。 然后,可以在类声明的主体中使用类型参数来定义类成员。 在以下示例中,Pair 的类型参数是 TFirst TSecond

            public class Pair<TFirst, TSecond>
            {
                public TFirst First { get; }
                public TSecond Second { get; }
                
                public Pair(TFirst first, TSecond second) => 
                    (First, Second) = (first, second);
            }
            
            
            

            声明为需要使用类型参数的类类型被称为 泛型类类型。 结构、接口和委托类型也可以是泛型。 使用泛型类时,必须为每个类型参数提供类型自变量:

            var pair = new Pair<int, string>(1, "two");
            int i = pair.First;     //TFirst int
            string s = pair.Second; //TSecond string
            
            
            

            包含类型自变量的泛型类型(如上面的 Pair<int,string> )被称为 构造泛型类型。

            2、基类

            类声明可以指定基类。 在类名和类型参数后面加上冒号和基类的名称。 省略基类规范与从 object 类型派生相同。 在以下示例中,Point3D 的基类是 Point 在第一个示例中,Point 的基类是 object:

            public class Point3D : Point
            {
                public int Z { get; set; }
                
                public Point3D(int x, int y, int z) : base(x, y)
                {
                    Z = z;
                }
            }
            
            
            

            类继承其基类的成员。 继承意味着一个类隐式包含其基类的几乎所有成员。 类不继承实例、静态构造函数以及终结器。 派生类可以在其继承的成员中添加新成员,但无法删除继承成员的定义。 在上面的示例中,Point3D 从 Point 继承了 X 和 Y 成员,每个 Point3D 实例均包含三种属性(X、Y 和 Z)。

            可以将类类型隐式转换成其任意基类类型。 类类型的变量可以引用相应类的实例或任意派生类的实例。

             例如,类声明如上,Point 类型的变量可以引用 Point 或 Point3D:

            Point a = new(10, 20);
            Point b = new Point3D(10, 20, 30);
            
            
            

            二、结构

            类定义可支持继承和多形性的类型。 它们使你能够基于派生类的层次结构创建复杂的行为。 相比之下,结构类型是较为简单的类型,其主要目的是存储数据值。 结构不能声明基类型;它们从 System.ValueType 隐式派生。 不能从 struct 类型派生其他 struct 类型。 这些类型已隐式密封。

            public struct Point
            {
                public double X { get; }
                public double Y { get; }
                
                public Point(double x, double y) => (X, Y) = (x, y);
            }
            
            
            

            三、接口

            接口定义了可由类和结构实现的协定*。 定义接口来声明在不同类型之间共享的功能。 例如,System.Collections.Generic.IEnumerable<T> 接口定义了一个遍历集合(如数组)中所有项的一致方法。 接口可以包含方法、属性、事件和索引器。 接口通常不提供所定义成员的实现,仅指定必须由实现接口的类或结构提供的成员。

            接口可以采用 多重继承。 在以下示例中,接口 IComboBox 同时继承自 ITextBox IListBox

            interface IControl
            {
                void Paint();
            }
            
            interface ITextBox : IControl
            {
                void SetText(string text);
            }
            
            interface IListBox : IControl
            {
                void SetItems(string[] items);
            }
            
            interface IComboBox : ITextBox, IListBox { }
            
            
            

            类和结构可以实现多个接口。 在以下示例中,类 EditBox 同时实现 IControl IDataBound

            interface IDataBound
            {
                void Bind(Binder b);
            }
            
            public class EditBox : IControl, IDataBound
            {
                public void Paint() { }
                public void Bind(Binder b) { }
            }
            
            
            

            当类或结构实现特定接口时,此类或结构的实例可以隐式转换成相应的接口类型。 例如:

            EditBox editBox = new();
            IControl control = editBox;
            IDataBound dataBound = editBox;
            
            
            

            四、枚举

            枚举类型定义了一组常数值。 以下 enum 声明了定义不同根蔬菜的常数:

            public enum SomeRootVegetable
            {
                HorseRadish,
                Radish,
                Turnip
            }
            
            
            

            还可以定义一个 enum 作为标志组合使用。 以下声明为四季声明了一组标志。

            可以随意搭配季节组合,包括 All 值(包含所有季节):

            [Flags]
            public enum Seasons
            {
                None = 0,
                Summer = 1,
                Autumn = 2,
                Winter = 4,
                Spring = 8,
                All = Summer | Autumn | Winter | Spring
            }
            
            
            

            以下示例显示了前面两个枚举的声明:

            var turnip = SomeRootVegetable.Turnip;
            
            var spring = Seasons.Spring;
            var startingOnEquinox = Seasons.Spring | Seasons.Autumn;
            var theYear = Seasons.All;
            
            
            

            五、可为 null 的类型

            任何类型的变量都可以声明为“不可为 null”或“可为 null”。 可为 null 的变量包含一个额外的 null 值,表示没有值。 可为 null 的值类型(结构或枚举)由 System.Nullable<T> 表示。 不可为 null 和可为 null 的引用类型都由基础引用类型表示。 这种区别由编译器和某些库读取的元数据体现。 当可为 null 的引用在没有先对照 null 检查其值的情况下取消引用时,编译器会发出警告。 当对不可为 null 的引用分配了可能为 null 的值时,编译器也会发出警告。 以下示例声明了“可为 null 的 int”,并将其初始化为 null。 然后将值设置为 5。 该示例通过“可为 null 的字符串” ** 演示了同一概念。

            int? optionalInt = default; 
            optionalInt = 5;
            string? optionalText = default;
            optionalText = "Hello World.";
            
            
            

            六、元组

            C# 支持元组,后者提供了简洁的语法来将多个数据元素分组成一个轻型数据结构。

            通过声明 ( 和 ) 之间的成员的类型和名称来实例化元组,如下例所示:

            (double Sum, int Count) t2 = (4.5, 3);
            Console.WriteLine($"Sum of {t2.Count} elements is {t2.Sum}.");
            //Output:
            //Sum of 3 elements is 4.5.
            
            
            

            元组为具有多个成员的数据结构提供了一种替代方法

            声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。