C#如何继承基类并覆写静态属性?CRUD代码复用方案
问题解答
首先明确:C#中无法通过继承覆写静态属性。静态成员是绑定到类本身的,子类定义的static string TableName和基类的static string TableName是完全独立的两个成员,基类的ReadAll方法只会调用自身的TableName,因此会出现null的情况。
下面提供几种可行的方案来减少CRUD代码重复:
方案一:泛型仓储+自定义表名特性
通过自定义特性标记实体类对应的表名,再用泛型仓储类统一实现CRUD逻辑,利用反射获取表名。
- 定义表名特性:
[AttributeUsage(AttributeTargets.Class, Inherited = false)] public class TableNameAttribute : Attribute { public string Name { get; } public TableNameAttribute(string name) { Name = name; } }
- 定义实体基类:
public abstract class BaseEntity : IIdWithName { public int Id { get; set; } public string Name { get; set; } }
- 实现泛型仓储类:
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(); } }
- 标记实体类并使用:
[TableName("SubClass1TableName")] public class SubClass1 : BaseEntity { // 可添加子类专属属性 } // 调用示例 var subClass1Items = EntityRepository<SubClass1>.ReadAll();
方案二:利用ORM框架(如Entity Framework Core)
如果项目允许引入ORM框架,EF Core可以完全替代手写CRUD代码,自动处理表名映射和数据操作:
- 定义实体类并标记表名(或通过Fluent API配置):
[Table("SubClass1TableName")] public class SubClass1 : IIdWithName { public int Id { get; set; } public string Name { get; set; } }
- 配置DbContext:
public class AppDbContext : DbContext { public DbSet<SubClass1> SubClass1s { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer("你的数据库连接字符串"); } }
- 执行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
相关产品推荐
相关产品推荐

