跳至页脚内容
Iron Academy Logo
学习 C#
学习 C#

其他类别

了解 C# 抽象类

Tim Corey
19m 59s

C# 中的抽象类是一个基本概念,经常会引起开发人员的疑问。 在他的视频" C# 抽象类 - 它们是什么、如何使用它们以及最佳实践"中,Tim Corey 深入探讨了抽象类是什么、如何使用它们以及最佳实践。 本文总结了他视频中的要点,并附有时间戳以供参考。

简介

Tim(0:00)解释说,抽象类的目的、功能和重要性经常受到质疑。 他将抽象类描述为介于完整基类和接口之间的混合体,在功能上介于两者之间。

应用程序演示

在(0:59),Tim 通过演示应用程序来演示抽象类。 该应用程序包含一个控制台应用程序和一个类库,其中包含两个模拟数据库操作的数据访问类。 这些类具有加载和保存数据的方法,Tim 用这些方法来说明抽象类、基类和接口之间的异同。

以下是基类和派生类的初始代码:

// Base Class Definition
public class DataAccess
{
    // Method to load the connection string
    public string LoadConnectionString()
    {
        Console.WriteLine("Loading the connection string...");
        return "Test Connection String";
    }

    // Method to load data
    public void LoadData()
    {
        Console.WriteLine("Loading data...");
    }

    // Method to save data
    public void SaveData()
    {
        Console.WriteLine("Saving data...");
    }
}

// Derived class that inherits from DataAccess
public class SQLDataAccess : DataAccess
{
    // Overriding LoadData method to specify SQL data loading
    public new void LoadData()
    {
        Console.WriteLine("Loading SQL data...");
    }

    // Overriding SaveData method to specify SQL data saving
    public new void SaveData()
    {
        Console.WriteLine("Saving SQL data...");
    }
}

// Derived class that inherits from DataAccess
public class SQLiteDataAccess : DataAccess
{
    // Overriding LoadData method to specify SQLite data loading
    public new void LoadData()
    {
        Console.WriteLine("Loading SQLite data...");
    }

    // Overriding SaveData method to specify SQLite data saving
    public new void SaveData()
    {
        Console.WriteLine("Saving SQLite data...");
    }
}
// Base Class Definition
public class DataAccess
{
    // Method to load the connection string
    public string LoadConnectionString()
    {
        Console.WriteLine("Loading the connection string...");
        return "Test Connection String";
    }

    // Method to load data
    public void LoadData()
    {
        Console.WriteLine("Loading data...");
    }

    // Method to save data
    public void SaveData()
    {
        Console.WriteLine("Saving data...");
    }
}

// Derived class that inherits from DataAccess
public class SQLDataAccess : DataAccess
{
    // Overriding LoadData method to specify SQL data loading
    public new void LoadData()
    {
        Console.WriteLine("Loading SQL data...");
    }

    // Overriding SaveData method to specify SQL data saving
    public new void SaveData()
    {
        Console.WriteLine("Saving SQL data...");
    }
}

// Derived class that inherits from DataAccess
public class SQLiteDataAccess : DataAccess
{
    // Overriding LoadData method to specify SQLite data loading
    public new void LoadData()
    {
        Console.WriteLine("Loading SQLite data...");
    }

    // Overriding SaveData method to specify SQLite data saving
    public new void SaveData()
    {
        Console.WriteLine("Saving SQLite data...");
    }
}

创建基类

Tim 在 (3:21) 处解释了如何创建基类。 他重构代码,将DataAccess的基类中。 通过继承这个基类,像SQLiteDataAccess这样的其他类可以访问这些共享的方法,从而减少代码重复。

将基类抽象化

Tim 在 (5:56) 将基类转换为抽象类,以演示两者之间的区别。 他将DataAccess更改为抽象类,防止其被直接实例化。 相反,只有从这个抽象类继承的类,如SQLDataAccess,才能实现其方法并使用其共享功能。

以下是当DataAccess变为抽象类时代码的变化:

// Abstract Base Class Definition
public abstract class AbstractDataAccess
{
    // Shared method to load connection string
    public string LoadConnectionString()
    {
        Console.WriteLine("Loading the connection string...");
        return "Test Connection String";
    }

    // Abstract methods that must be implemented by derived classes
    public abstract void LoadData();
    public abstract void SaveData();
}
// Abstract Base Class Definition
public abstract class AbstractDataAccess
{
    // Shared method to load connection string
    public string LoadConnectionString()
    {
        Console.WriteLine("Loading the connection string...");
        return "Test Connection String";
    }

    // Abstract methods that must be implemented by derived classes
    public abstract void LoadData();
    public abstract void SaveData();
}

抽象类中的接口部分

Tim 在 (8:34) 解释了抽象类如何融合接口和基类的特性。 他在抽象类中声明抽象方法,如public abstract void SaveData();,而不实现它们。 这样就确保了任何派生类都必须实现这些方法,类似于接口的工作方式。

抽象类中的方法重写

Tim 在 (12:56) 讨论了如何重写抽象类中的方法。 他展示了可以在基类中将一个方法声明为virtual,允许派生类重写它。 这种方法为派生类中方法的实现和扩展提供了灵活性。

以下是派生类的代码,展示了方法重写:

// Derived class from abstract base class
public class SQLDataAccessWithAbstract : AbstractDataAccess
{
    // Implementing the abstract LoadData method
    public override void LoadData()
    {
        Console.WriteLine("Loading SQL data...");
    }

    // Implementing the abstract SaveData method
    public override void SaveData()
    {
        Console.WriteLine("Saving SQL data...");
    }
}
// Derived class from abstract base class
public class SQLDataAccessWithAbstract : AbstractDataAccess
{
    // Implementing the abstract LoadData method
    public override void LoadData()
    {
        Console.WriteLine("Loading SQL data...");
    }

    // Implementing the abstract SaveData method
    public override void SaveData()
    {
        Console.WriteLine("Saving SQL data...");
    }
}

何时使用抽象类

Tim 在 (16:01) 建议,抽象类不应该每天都使用,但在特定情况下很有价值。 他告诫人们不要仅仅因为两个类共享相似的代码就使用抽象类。 相反,他强调要保持"is a"关系,并建议在适当的时候考虑使用辅助方法或类来共享代码。

以下是演示用法的主要程序代码:

// Main Program
class Program
{
    static void Main(string[] args)
    {
        // Using Base Class
        SQLDataAccess sqlData = new SQLDataAccess();
        Console.WriteLine(sqlData.LoadConnectionString());
        sqlData.LoadData();
        sqlData.SaveData();

        Console.WriteLine("--------------------------");

        // Using Derived Class from Abstract Base Class
        SQLDataAccessWithAbstract sqlDataAbstract = new SQLDataAccessWithAbstract();
        Console.WriteLine(sqlDataAbstract.LoadConnectionString());
        sqlDataAbstract.LoadData();
        sqlDataAbstract.SaveData();

        Console.WriteLine("--------------------------");

        // You can't instantiate Abstract Base Class directly
        // AbstractDataAccess abstractData = new AbstractDataAccess(); 
        // Error: Cannot create an instance of the abstract class
    }
}
// Main Program
class Program
{
    static void Main(string[] args)
    {
        // Using Base Class
        SQLDataAccess sqlData = new SQLDataAccess();
        Console.WriteLine(sqlData.LoadConnectionString());
        sqlData.LoadData();
        sqlData.SaveData();

        Console.WriteLine("--------------------------");

        // Using Derived Class from Abstract Base Class
        SQLDataAccessWithAbstract sqlDataAbstract = new SQLDataAccessWithAbstract();
        Console.WriteLine(sqlDataAbstract.LoadConnectionString());
        sqlDataAbstract.LoadData();
        sqlDataAbstract.SaveData();

        Console.WriteLine("--------------------------");

        // You can't instantiate Abstract Base Class directly
        // AbstractDataAccess abstractData = new AbstractDataAccess(); 
        // Error: Cannot create an instance of the abstract class
    }
}

结论

Tim Corey 对C# 抽象类的深入剖析,清晰而实用地阐释了抽象类的用途、功能和实际应用。 通过他的演示应用程序,他展示了抽象类如何弥合基类和接口之间的差距,使开发人员能够创建灵活且易于维护的代码结构。

Tim 通过强调最佳实践,例如在正确的场景中使用抽象类并避免过度使用,为开发人员提供了做出明智设计选择的工具。 掌握了这些概念,开发人员可以提高面向对象编程技能,并构建强大的 C# 应用程序。

Hero Worlddot related to 了解 C# 抽象类
Hero Affiliate related to 了解 C# 抽象类

分享您的所爱,赚取更多收入

您为使用 .NET、C#、Java、Python 或 Node.js 的开发人员创建内容吗?将您的专业知识转化为额外收入!

钢铁支援团队

我们每周 5 天,每天 24 小时在线。
聊天
电子邮件
打电话给我