You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将C#的AccountType类改造为基类,实现子类复用属性与方法?

改造为泛型基类实现复用

我来帮你把这个AccountType类改造成一个可复用的泛型基类,这样其他子类只需要指定对应的表名,就能继承所有通用的属性和方法,并且所有方法都会返回正确的子类类型。下面是具体的改造方案:

第一步:创建泛型抽象基类 BaseEntity<T>

我们通过泛型保证方法返回正确的子类类型,同时用抽象属性让子类指定表名。基类会包含所有通用的属性、克隆方法和数据操作逻辑,这里分两种C#版本适配:

适配C# 8.0+(支持静态抽象成员)

这个版本可以直接用静态抽象属性让子类指定表名,代码更简洁:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;

public abstract class BaseEntity<T> where T : BaseEntity<T>, new()
{
    // 每个子类独立的静态缓存列表(泛型静态字段按封闭类型隔离)
    private static List<T> _entities = new List<T>();
    public static List<T> Entities => _entities;

    // 通用属性
    private int _id = -1;
    public int Id
    {
        get => _id;
        set => _id = value;
    }

    private string _name = "";
    public string Name
    {
        get => _name;
        set => _name = value;
    }

    // 静态抽象表名,子类必须实现
    protected abstract static string TableName { get; }

    // 克隆方法,返回子类实例
    public T Clone()
    {
        return (T)MemberwiseClone();
    }

    // 填充单条数据为子类实例
    protected static T Fill(DataRow row)
    {
        if (row == null) return null;

        int id = Convert.ToInt32(row["id"].ToString());
        string name = row["name"].ToString();

        T entity = new T();
        entity._id = id;
        entity._name = name;
        return entity;
    }

    // 填充多条数据为子类列表
    protected static List<T> FillAll(DataRowCollection rows)
    {
        List<T> entities = new List<T>();
        foreach (DataRow row in rows)
        {
            T entity = Fill(row);
            if (entity != null)
                entities.Add(entity);
        }
        return entities;
    }

    // 获取所有数据(优先用缓存)
    public static List<T> GetAll()
    {
        if (_entities.Count > 0)
            return _entities;

        List<T> entities = new List<T>();
        string query = $"SELECT * FROM {T.TableName} WHERE id > -1 ORDER BY name";
        DataSet result = Global.Db.ExecuteQuery(query);
        
        if (result == null || result.Tables[0] == null || result.Tables[0].Rows.Count < 1)
            return entities;

        entities = FillAll(result.Tables[0].Rows);
        _entities = entities;
        return entities;
    }

    // 根据ID获取单条数据(优先缓存)
    public static T GetById(int id)
    {
        foreach (T entity in _entities)
        {
            if (entity.Id == id)
                return entity;
        }

        T entityResult = null;
        string query = $"SELECT * FROM {T.TableName} WHERE id = {id}";
        DataSet result = Global.Db.ExecuteQuery(query);
        
        if (result != null && result.Tables[0] != null && result.Tables[0].Rows.Count > 0)
        {
            entityResult = Fill(result.Tables[0].Rows[0]);
        }
        return entityResult;
    }

    // 加载数据到缓存
    public static void Load()
    {
        _entities = GetAll();
    }

    // 保存新数据(修正了原代码的参数名错误)
    public void Save()
    {
        string query = $"INSERT INTO {TableName} (name) VALUES (@name)";
        SQLiteCommand command = new SQLiteCommand
        {
            CommandText = query,
            CommandType = CommandType.Text
        };
        command.Parameters.Add(new SQLiteParameter("@name", _name));
        Global.Db.ExecuteNonQuery(command);
    }

    // 更新现有数据
    public void Update()
    {
        string query = $"UPDATE {TableName} SET name = @name WHERE id = @id";
        SQLiteCommand command = new SQLiteCommand
        {
            CommandText = query,
            CommandType = CommandType.Text
        };
        command.Parameters.Add(new SQLiteParameter("@id", _id));
        command.Parameters.Add(new SQLiteParameter("@name", _name));
        Global.Db.ExecuteNonQuery(command);
    }
}

适配旧版本C#(不支持静态抽象成员)

如果你的项目用的是C# 7.3及以下,可以通过反射获取子类的静态表名字段:

// 基类中调整表名获取逻辑,以GetAll方法为例:
public static List<T> GetAll()
{
    if (_entities.Count > 0)
        return _entities;

    // 通过反射获取子类的静态tableName字段
    var tableNameField = typeof(T).GetField("tableName", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
    string tableName = tableNameField?.GetValue(null) as string ?? string.Empty;

    List<T> entities = new List<T>();
    string query = $"SELECT * FROM {tableName} WHERE id > -1 ORDER BY name";
    DataSet result = Global.Db.ExecuteQuery(query);
    
    if (result == null || result.Tables[0] == null || result.Tables[0].Rows.Count < 1)
        return entities;

    entities = FillAll(result.Tables[0].Rows);
    _entities = entities;
    return entities;
}

第二步:子类的实现

子类只需要继承基类,指定对应的表名即可,无需编写其他重复代码:

C# 8.0+子类示例

public class AccountType : BaseEntity<AccountType>
{
    protected override static string TableName => "accountTypes";
}

// 另一个子类示例
public class UserType : BaseEntity<UserType>
{
    protected override static string TableName => "userTypes";
}

旧版本C#子类示例

public class AccountType : BaseEntity<AccountType>
{
    private static string tableName = "accountTypes";
}

// 另一个子类示例
public class UserType : BaseEntity<UserType>
{
    private static string tableName = "userTypes";
}

关键改造点说明

  • 泛型约束:where T : BaseEntity<T>, new() 确保T是继承自BaseEntity<T>的子类,且有无参构造函数,让基类可以创建子类实例。
  • 静态缓存隔离:泛型的静态字段_entities会为每个子类创建独立缓存,不同子类的缓存不会互相干扰。
  • 表名解耦:通过静态抽象属性(或静态字段+反射)让子类指定自己的数据库表名,基类无需关心具体表名。
  • 类型安全:所有方法(如GetAll、Clone)都返回T类型,调用时直接得到子类实例,无需强制转换。
  • 错误修正:修复了原Save方法中参数名错误(@currencyPair改为@name)。

这样改造后,任何需要类似功能的子类只需要继承BaseEntity<T>并指定表名,就能拥有所有通用的属性和数据操作方法,完全符合你的需求。

内容的提问来源于stack exchange,提问作者Luca

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:15:51