学习c#的第十二天

目录

C# 类(Class)

类的定义

getter和setter方法

成员函数和封装

C# 中的构造函数

C# 中的析构函数

C# 类的静态成员

c#的 this 关键词

C# 继承

基类和派生类

基类的初始化

C# 多重继承


C# 类(Class)

当你定义一个类时,你定义了一个数据类型的蓝图。这实际上并没有定义任何的数据,但它定义了类的名称意味着什么,也就是说,类的对象由什么组成及在这个对象上可执行什么操作。对象是类的实例。构成类的方法和变量称为类的成员。

类的定义

在C#中,定义一个类通常包括以下几个部分:

  1. 访问修饰符(Access Modifier):用于控制类的访问级别,常见的包括 public(公共)、private(私有)、protected(受保护的)等。

  2. class关键字:用于声明一个类。

  3. 类名:类名遵循大驼峰命名法,用于标识这个类。

  4. 类体:类体由一对大括号{}包围,里面包含了类的字段、属性、方法等成员以及相关的代码块。

下面是一个简单的类定义示例:

public class Person
{
    // 字段
    private string name;
    private int age;

    // 属性
    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public int Age
    {
        get { return age; }
        set { age = value; }
    }

    // 方法
    public void Introduce()
    {
        Console.WriteLine("我的名字是 " + name + " 而我今年 " + age + " 岁了");
    }
}

在这个示例中,我们定义了一个名为Person的类。它具有name和age两个私有字段,分别表示人的姓名和年龄。同时,我们定义了Name和Age两个公共属性,用于对外提供对私有字段的访问。最后,还定义了一个Introduce方法,用于介绍个人信息。

getter和setter方法

在C#中,getter和setter方法通常用于访问和修改属性的值。Getter方法用于获取属性的值,而setter方法用于设置属性的值。在C#中,这些方法可以通过属性的定义来自动生成,也可以手动编写。

下面是一个简单的示例,展示了如何在C#中使用getter和setter方法:

public class MyClass
{
    private int myProperty;

    public int MyProperty
    {
        get
        {
            // getter方法,用于获取属性的值
            return myProperty;
        }
        set
        {
            // setter方法,用于设置属性的值
            myProperty = value;
        }
    }
}

在这个示例中,MyProperty是一个公共属性,它包含了一个getter方法和一个setter方法。当其他代码尝试获取MyClass实例的MyProperty属性时,将调用getter方法;当尝试对MyClass实例的MyProperty属性进行赋值时,将调用setter方法。

在实际应用中,getter和setter方法可以用于执行验证、触发事件或执行其他与属性相关的逻辑。同时,C#也提供了自动属性的机制,使得可以更加简洁地定义属性并自动生成对应的getter和setter方法。

成员函数和封装

在面向对象编程中,成员函数是定义在类中的函数,也被称为方法。成员函数可以访问类的成员(字段和属性),并且可以执行特定的操作。

封装是面向对象编程的一个重要概念,它指的是将数据和操作封装在类中,并通过公共接口来访问和操作这些数据。封装的目的是隐藏类的内部实现细节,使得类的使用者只需要关注如何使用类的公共接口,而不需要了解其内部的具体实现。

在C#中,我们可以使用访问修饰符来控制类的成员的可见性和访问级别。常用的访问修饰符包括:

  1. public:可以从任何地方访问。
  2. private:只能在当前类内部访问。
  3. protected:只能在当前类及其派生类中访问。
  4. internal:只能在当前程序集中访问。
  5. protected internal:同时具有 protected 和 internal 的访问级别,可以在当前程序集及其派生类中访问。

通过合理地使用访问修饰符,我们可以实现封装的效果。通常情况下,将类的成员设置为私有的,然后通过公共的成员函数提供对这些私有成员的访问和操作。

以下示例演示了封装的概念:

using System;

public class Person
{
    private string name;
    private int age;

    public void SetName(string newName)
    {
        name = newName;
    }

    public void SetAge(int newAge)
    {
        if (newAge >= 0)
        {
            age = newAge;
        }
        else
        {
            Console.WriteLine("年龄不能是负数。");
        }
    }

    public void Introduce()
    {
        Console.WriteLine("我的名字是 " + name + " 而我今年 " + age + " 岁了。");
    }
}

class Program
{
    static void Main()
    {
        // 创建 Person 对象
        Person person1 = new Person();

        // 设置姓名和年龄
        person1.SetName("杰瑞");
        person1.SetAge(25);

        // 调用 Introduce 方法
        person1.Introduce();
    }
}

在这个示例中,我们首先定义了一个Person类,包括私有字段name和age,以及公共的成员函数SetName、SetAge和Introduce。然后,在Program类中的Main方法中,我们创建了一个Person对象person1,并通过调用公共的成员函数来设置其姓名和年龄,并最终调用Introduce方法来展示这个人的信息。

通过这种方式,我们实现了封装,隐藏了类的内部实现细节(私有字段),外部只能通过公共的接口(公共成员函数)来访问和操作类的数据。

C# 中的构造函数

在C#中,构造函数是一种特殊的方法,用于在创建类的新实例时初始化对象。构造函数的名称必须与类的名称相同,并且没有返回类型。它可以包含参数,这些参数用于指定在创建对象时需要提供的初始数据。

下面是一个简单的示例,展示了如何在C#中定义和使用构造函数:

using System;
public class Person
{
    private string name;
    private int age;

    // 构造函数
    public Person(string initialName, int initialAge)
    {
        name = initialName;
        age = initialAge;
    }

    public void Introduce()
    {
        Console.WriteLine("我的名字是 " + name + " 而我今年 " + age + " 岁了。");
    }
}

class Program
{
    static void Main()
    {
        // 使用构造函数创建 Person 对象
        Person person1 = new Person("杰瑞", 25);

        // 调用 Introduce 方法
        person1.Introduce();
    }
}

在上面的示例中,我们为Person类添加了一个构造函数,该构造函数接受两个参数initialName和initialAge,用于初始化name和age字段。在Main方法中,我们使用这个构造函数来创建一个新的Person对象person1,并传入初始的姓名和年龄信息。

通过使用构造函数,我们可以在创建对象时就提供必要的初始化数据,从而确保对象在被创建后处于一个合法的状态。

C# 中的析构函数

在C#中,析构函数是类的一个特殊成员函数,它在对象的生命周期结束时被调用,用于执行一些清理操作,比如释放资源、关闭文件等。析构函数的名称以波浪形(~)作为前缀,与类的名称相同,并且没有返回值和参数。

下面是一个简单的示例,展示了在C#中如何定义和使用析构函数:

public class MyClass
{
    // 析构函数
    ~MyClass()
    {
        // 执行清理操作
        Console.WriteLine("调用析构函数,执行清理。");
    }
}

在上面的示例中,~MyClass()就是MyClass类的析构函数,用于在对象被销毁时执行清理操作。

需要注意的是,在实际开发中,由于C#通常依靠垃圾回收来释放对象,所以我们很少需要使用析构函数手动释放资源。相反,通常会使用IDisposable接口和Dispose方法来实现资源的释放。因此,析构函数在C#中并不像其他语言(如C++)中那样常见。

C# 类的静态成员

在C#中,使用static关键字可以将类的成员定义为静态的。静态成员只会在内存中存在一份副本,无论创建了多少个类的实例。这使得静态成员在全局范围内都可被访问,并且不需要通过类的实例来访问。

1、静态字段(Static Fields):静态字段用static关键字声明,可以在成员函数或类的定义外部进行初始化。

public class MyClass
{
    public static int staticField = 10;
}

2、静态方法(Static Methods):静态方法用static关键字声明,可以直接通过类名调用,无需创建类的实例。

public class MyClass
{
    public static void StaticMethod()
    {
        Console.WriteLine("这是一种静态方法。");
    }
}

3、静态属性(Static Properties):静态属性与静态字段类似,但通常使用属性的形式访问。

public class MyClass
{
    private static int staticProperty;

    public static int StaticProperty
    {
        get { return staticProperty; }
        set { staticProperty = value; }
    }
}

4、静态构造函数(Static Constructor):静态构造函数用于初始化类的静态成员,在类被加载时执行,并且只执行一次。

public class MyClass
{
    static MyClass()
    {
        // 静态构造函数
        Console.WriteLine("调用静态构造函数。");
    }
}

静态成员在很多情况下都非常有用,比如用于定义常量、提供全局访问点以及执行与类相关的操作。但需要注意,过度使用静态成员可能导致全局状态难以管理和测试。

c#的 this 关键词

在 C# 中,this 关键字是一个特殊的引用,用于表示当前类的实例。它可以在类的方法和构造函数中使用,以便访问当前实例的成员变量、属性和方法。下面我将详细介绍 this 关键字的用法:

1、访问成员变量和属性:在类的方法中,可以使用 this 关键字来引用当前实例的成员变量和属性。这样做可以帮助区分成员变量和方法参数之间的同名情况。

class MyClass
{
    private int value;

    public void SetValue(int value)
    {
        this.value = value; // 使用this关键字来引用当前实例的value成员变量
    }

    public int GetValue()
    {
        return this.value; // 使用this关键字来引用当前实例的value成员变量
    }
}

2、在构造函数中调用其他构造函数:在一个构造函数中,可以使用 this 关键字来调用同一个类的其他构造函数。这种方式被称为构造函数的重载(constructor overloading),它可以减少代码重复,并且确保在不同的构造函数中执行相同的初始化逻辑。

class MyClass
{
    private int value;

    public MyClass(int value)
    {
        this.value = value;
    }

    public MyClass() : this(0) // 调用另一个构造函数来进行初始化
    {
    }
}

3、传递当前实例给其他方法或构造函数:在需要将当前实例作为参数传递给其他方法或构造函数时,可以使用 this 关键字来引用当前实例自身。

总之,在 C# 中,this 关键字用于表示当前类的实例,并且可以用来访问当前实例的成员变量、属性和方法,以及在构造函数中调用其他构造函数。

using System;

class MyClass
{
    private int value;

    public MyClass(int value)
    {
        this.value = value; // 使用this关键字来引用当前实例的value成员变量
    }

    public MyClass() : this(0) // 调用另一个构造函数来进行初始化
    {
    }

    public void SetValue(int value)
    {
        this.value = value; // 使用this关键字来引用当前实例的value成员变量
    }

    public int GetValue()
    {
        return this.value; // 使用this关键字来引用当前实例的value成员变量
    }
}

class Program
{
    static void Main()
    {
        MyClass obj1 = new MyClass(10);
        Console.WriteLine(obj1.GetValue()); // 输出 10

        MyClass obj2 = new MyClass();
        Console.WriteLine(obj2.GetValue()); // 输出 0

        obj2.SetValue(20);
        Console.WriteLine(obj2.GetValue()); // 输出 20
    }
}

在这个示例中,我们定义了一个名为 MyClass 的类,它包含一个私有成员变量 value 和若干方法。在构造函数中,我们使用 this 关键字来引用当前实例的成员变量,并且还展示了通过 this 调用其他构造函数的方式。在 Main 方法中,我们创建了 MyClass 的实例,并演示了使用 this 关键字来访问实例的成员方法。 

C# 继承

基类和派生类

在面向对象编程中,基类和派生类是面向对象的核心概念之一。在C#中,基类通常被称为父类(base class)或超类(super class),而派生类通常被称为子类(derived class)。让我通过一个简单的例子来说明这个概念。

假设我们有一个基类 Animal,它包含了一些所有动物都具有的属性和行为,比如 Eat 和 Sleep。然后我们可以创建一个派生类 Dog,它继承了 Animal 的属性和行为,并且可以具有自己的特定属性和行为,比如 Bark。

一个类可以派生自多个类或接口,这意味着它可以从多个基类或接口继承数据和函数。

C# 中创建派生类的语法如下:

<访问修饰符> class <基类>
{
 ...
}
class <派生类> : <基类>
{
 ...
}

关于继承的几点: 

  1. 继承的语法,C# 中使用 : 来表示继承关系,子类通过 : 后面指定父类,然后在大括号中定义子类自己的成员。
  2. 子类继承了父类中的所有字段、属性和方法,但需要注意的是,父类中的私有成员(private)不会被子类继承,而只能在父类内部访问。另外,子类也可以重写(override)父类的虚方法或抽象方法。
  3. 一个类确实可以有多个子类,这符合面向对象编程的多态性原则。每个子类都可以有自己的特性和行为,并且可以共享父类的特性和行为。
  4. 一个类在继承另一个类的同时,确实也可以被其他类继承,形成多层继承关系。
  5. 在 C# 中,所有的类确实都直接或间接地继承自 Object 类。Object 是 .NET Framework 类层次结构的根,它定义了所有对象的通用行为,包括如 ToString、Equals、GetHashCode 等方法。

假设,有一个基类 Shape,它的派生类是 Rectangle:

using System;

class MyClass
{
    class Shape
    {
        public void setWidth(int w)
        {
            width = w;
        }
        public void setHeight(int h)
        {
            height = h;
        }
        protected int width;
        protected int height;
    }

    // 派生类
    class Rectangle : Shape
    {
        public int getArea()
        {
            return (width * height);
        }
    }

    class RectangleTester
    {
        static void Main(string[] args)
        {
            Rectangle Rect = new Rectangle();

            Rect.setWidth(5);
            Rect.setHeight(7);

            // 打印对象的面积
            Console.WriteLine("总面积: {0}", Rect.getArea());
            Console.ReadKey();
        }
    }
}

当上面的代码被编译和执行时,它会产生下列结果:

总面积: 35

基类的初始化

在 C# 中,可以使用 base 关键字来初始化基类的成员。当一个类继承自另一个类时,基类的构造函数会在子类的构造函数中被隐式调用。你可以使用 base 关键字来访问基类的构造函数并传递参数。

以下是一个示例代码,演示了如何初始化基类的构造函数:

using System;

class MyClass
{
    class BaseClass
    {
        protected int baseValue;

        public BaseClass(int value)
        {
            baseValue = value;
            Console.WriteLine("基类构造函数");
        }
    }

    class DerivedClass : BaseClass
    {
        private int derivedValue;

        public DerivedClass(int baseValue, int derivedValue)
            : base(baseValue) // 使用 base 关键字初始化基类构造函数
        {
            this.derivedValue = derivedValue;
            Console.WriteLine("派生类构造函数");
        }

        public void PrintValues()
        {
            Console.WriteLine("基类值: " + baseValue);
            Console.WriteLine("派生值: " + derivedValue);
        }
    }

    class Program
    {
        static void Main()
        {
            DerivedClass derivedObj = new DerivedClass(10, 20);
            derivedObj.PrintValues();
        }
    }
}

在这个示例中,我们定义了一个基类 BaseClass 和一个派生类 DerivedClass。DerivedClass 继承自 BaseClass。在 DerivedClass 的构造函数中,我们使用 : base(baseValue) 来调用基类 BaseClass 的构造函数,并传递参数 baseValue。这样就可以确保基类的构造函数先于派生类的构造函数执行。

在 Main 方法中,我们创建了 DerivedClass 的实例 derivedObj,并通过调用 PrintValues 方法来打印基类和派生类的成员变量值。

当运行上面的代码时,输出将会是:

基类构造函数
派生类构造函数
基类值: 10
派生值: 20

C# 多重继承

在 C# 中,类不支持多重继承,也就是说一个类不能直接继承自多个类。这是因为多重继承容易引起复杂性和歧义,例如当多个基类中有相同的方法或属性时,编译器无法确定应该使用哪个基类的方法或属性。

然而,在 C# 中,可以使用接口来实现类似于多重继承的功能。一个类可以实现多个接口,从而获得多个接口的特性和行为。

下面是一个简单的示例,演示了如何在 C# 中使用接口来实现类似于多重继承的效果:

using System;

// 定义接口A
interface IA
{
    void MethodA();
}

// 定义接口B
interface IB
{
    void MethodB();
}

// 实现类同时实现接口A和接口B
class MyClass : IA, IB
{
    public void MethodA()
    {
        Console.WriteLine("方法A实施");
    }

    public void MethodB()
    {
        Console.WriteLine("方法B实施");
    }
}

class Program
{
    static void Main()
    {
        MyClass obj = new MyClass();
        obj.MethodA(); // 调用接口A的方法
        obj.MethodB(); // 调用接口B的方法
    }
}

在这个示例中,我们定义了两个接口 IA 和 IB,并且创建了一个名为 MyClass 的类,它同时实现了这两个接口。在 Main 方法中,我们创建了 MyClass 的实例,并调用了其实现的接口方法。

通过接口,我们可以让一个类具备多个特定行为,从而实现类似于多重继承的效果,同时避免了多重继承可能带来的复杂性和歧义问题。

你可能感兴趣的:(C#,学习,c#,开发语言)