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

C#如何继承基类并覆写静态属性?CRUD代码复用方案

问题解答

首先明确:C#中无法通过继承覆写静态属性。静态成员是绑定到类本身的,子类定义的static string TableName和基类的static string TableName是完全独立的两个成员,基类的ReadAll方法只会调用自身的TableName,因此会出现null的情况。

下面提供几种可行的方案来减少CRUD代码重复:

方案一:泛型仓储+自定义表名特性

通过自定义特性标记实体类对应的表名,再用泛型仓储类统一实现CRUD逻辑,利用反射获取表名。

  1. 定义表名特性:
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class TableNameAttribute : Attribute
{
    public string Name { get; }

    public TableNameAttribute(string name)
    {
        Name = name;
    }
}
  1. 定义实体基类:
public abstract class BaseEntity : IIdWithName
{
    public int Id { get; set; }
    public string Name { get; set; }
}
  1. 实现泛型仓储类:
public static class EntityRepository<T> where T : BaseEntity, new()
{
    private static readonly string _tableName;

    static EntityRepository()
    {
        // 从特性中获取表名
        var tableAttr = typeof(T).GetCustomAttribute<TableNameAttribute>();
        if (tableAttr == null)
            throw new InvalidOperationException($"实体类 {typeof(T).Name} 未标记 TableNameAttribute");
        
        _tableName = tableAttr.Name;
    }

    public static IEnumerable<T> ReadAll()
    {
        string sql = $"select * from {_tableName}";
        // 此处添加数据库读取逻辑,例如用Dapper或ADO.NET执行SQL并映射实体
        // 示例返回空列表,实际替换为真实逻辑
        return new List<T>();
    }

    // 可扩展其他CRUD方法
    public static T ReadById(int id)
    {
        string sql = $"select * from {_tableName} where Id = @Id";
        // 执行SQL并返回实体
        return new T();
    }
}
  1. 标记实体类并使用:
[TableName("SubClass1TableName")]
public class SubClass1 : BaseEntity
{
    // 可添加子类专属属性
}

// 调用示例
var subClass1Items = EntityRepository<SubClass1>.ReadAll();

方案二:利用ORM框架(如Entity Framework Core)

如果项目允许引入ORM框架,EF Core可以完全替代手写CRUD代码,自动处理表名映射和数据操作:

  1. 定义实体类并标记表名(或通过Fluent API配置):
[Table("SubClass1TableName")]
public class SubClass1 : IIdWithName
{
    public int Id { get; set; }
    public string Name { get; set; }
}
  1. 配置DbContext:
public class AppDbContext : DbContext
{
    public DbSet<SubClass1> SubClass1s { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("你的数据库连接字符串");
    }
}
  1. 执行CRUD操作:
using var dbContext = new AppDbContext();

// ReadAll
var allItems = dbContext.SubClass1s.ToList();
// ReadById
var item = dbContext.SubClass1s.Find(1);
// Insert
dbContext.SubClass1s.Add(new SubClass1 { Name = "测试名称" });
dbContext.SaveChanges();
// Update/Delete同理,直接操作DbSet即可

方案三:静态属性+反射获取子类表名

如果坚持用静态属性的方式,可以通过反射在泛型仓储中获取子类的静态TableName属性:

public abstract class BaseEntity : IIdWithName
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public static class EntityRepository<T> where T : BaseEntity
{
    private static readonly string _tableName;

    static EntityRepository()
    {
        // 反射获取子类的静态TableName属性
        var tableNameProp = typeof(T).GetProperty("TableName", BindingFlags.Public | BindingFlags.Static);
        if (tableNameProp == null || tableNameProp.PropertyType != typeof(string))
            throw new InvalidOperationException($"实体类 {typeof(T).Name} 必须定义公共静态字符串属性 TableName");
        
        _tableName = (string)tableNameProp.GetValue(null);
    }

    public static IEnumerable<T> ReadAll()
    {
        string sql = $"select * from {_tableName}";
        // 数据库操作逻辑
        return new List<T>();
    }
}

// 子类定义
public class SubClass1 : BaseEntity
{
    public static string TableName => "SubClass1TableName";
}

// 调用
var items = EntityRepository<SubClass1>.ReadAll();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 21:43:10