如何在C#中从泛型参数获取静态属性?
解决方案
针对你遇到的抽象静态成员无法实现的问题,这里提供几种实用的实现方案,适配不同的C#版本场景:
方案1:C# 10+.NET 6+ 类型安全实现(推荐)
C# 10开始支持接口中的抽象静态成员,完美解决你需要通过泛型类型获取静态缓存前缀的需求:
步骤1:定义约束接口
public interface IHasCacheKeyStem { abstract static string CacheKeyStem { get; } }
步骤2:重构DAO类
public abstract class Dao : IHasCacheKeyStem { public int Id { get; set; } public string CacheKey => $"{CacheKeyStem}-{Id}"; // 强制子类实现静态缓存前缀 public abstract static string CacheKeyStem { get; } } public class PersonDao : Dao { public static override string CacheKeyStem => "Person"; } public class CarDao : Dao { public static override string CacheKeyStem => "Car"; }
步骤3:修改处理器类
通过接口约束让泛型类型必须实现静态前缀,编译时即可校验:
public abstract class BaseProcessor<T> where T : Dao, IHasCacheKeyStem { private readonly ICache _myCache; protected BaseProcessor(ICache myCache) { _myCache = myCache; } public void AddToCache(T obj) { _myCache.Add(obj.CacheKey, obj); } public T RetrieveFromCache(int id) { string cacheKey = $"{T.CacheKeyStem}-{id}"; return _myCache.Get<T>(cacheKey); } }
方案2:兼容旧版本C#(无抽象静态支持)
如果你的项目使用C# 9及以下版本,可以选择以下两种子方案:
子方案2.1:处理器子类指定缓存前缀
通过抽象属性让处理器子类提供对应DAO的缓存前缀,避免反射开销:
public abstract class Dao { public int Id { get; set; } public abstract string CacheKeyStem { get; } public string CacheKey => $"{CacheKeyStem}-{Id}"; } public class PersonDao : Dao { public override string CacheKeyStem => "Person"; } public abstract class BaseProcessor<T> where T : Dao, new() { private readonly ICache _myCache; protected BaseProcessor(ICache myCache) { _myCache = myCache; } // 由具体处理器子类实现 protected abstract string CacheKeyStem { get; } public void AddToCache(T obj) { _myCache.Add(obj.CacheKey, obj); } public T RetrieveFromCache(int id) { string cacheKey = $"{CacheKeyStem}-{id}"; return _myCache.Get<T>(cacheKey); } } // 具体处理器示例 public class PersonProcessor : BaseProcessor<PersonDao> { protected override string CacheKeyStem => "Person"; public PersonProcessor(ICache myCache) : base(myCache) { } }
子方案2.2:反射获取静态前缀
通过反射一次性获取泛型类型的静态前缀,避免重复编写:
public abstract class Dao { public int Id { get; set; } public string CacheKey => $"{GetCacheKeyStem()}-{Id}"; protected string GetCacheKeyStem() { var prop = GetType().GetProperty("CacheKeyStem", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); return prop?.GetValue(null) as string ?? throw new InvalidOperationException("当前DAO类未定义静态CacheKeyStem属性"); } } public class PersonDao : Dao { public static string CacheKeyStem => "Person"; } public abstract class BaseProcessor<T> where T : Dao { private readonly ICache _myCache; private static readonly string _cacheKeyStem; // 静态构造函数中一次性反射获取,避免重复开销 static BaseProcessor() { var prop = typeof(T).GetProperty("CacheKeyStem", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); _cacheKeyStem = prop?.GetValue(null) as string ?? throw new InvalidOperationException($"类型{typeof(T)}未定义静态CacheKeyStem属性"); } protected BaseProcessor(ICache myCache) { _myCache = myCache; } public void AddToCache(T obj) { _myCache.Add(obj.CacheKey, obj); } public T RetrieveFromCache(int id) { string cacheKey = $"{_cacheKeyStem}-{id}"; return _myCache.Get<T>(cacheKey); } }
方案3:自定义属性标记前缀
通过自定义特性标记DAO类的缓存前缀,实现配置与代码分离:
// 定义缓存前缀特性 [AttributeUsage(AttributeTargets.Class, Inherited = false)] public class CacheKeyStemAttribute : Attribute { public string Stem { get; } public CacheKeyStemAttribute(string stem) => Stem = stem; } // 重构DAO类 public abstract class Dao { public int Id { get; set; } public string CacheKey => $"{GetCacheKeyStem()}-{Id}"; protected string GetCacheKeyStem() { var attr = GetType().GetCustomAttribute<CacheKeyStemAttribute>(); return attr?.Stem ?? throw new InvalidOperationException("当前DAO类未标记CacheKeyStemAttribute"); } } // 标记DAO类 [CacheKeyStem("Person")] public class PersonDao : Dao { } [CacheKeyStem("Car")] public class CarDao : Dao { } // 处理器类实现 public abstract class BaseProcessor<T> where T : Dao { private readonly ICache _myCache; private static readonly string _cacheKeyStem; static BaseProcessor() { var attr = typeof(T).GetCustomAttribute<CacheKeyStemAttribute>(); _cacheKeyStem = attr?.Stem ?? throw new InvalidOperationException($"类型{typeof(T)}未标记CacheKeyStemAttribute"); } protected BaseProcessor(ICache myCache) { _myCache = myCache; } public void AddToCache(T obj) { _myCache.Add(obj.CacheKey, obj); } public T RetrieveFromCache(int id) { string cacheKey = $"{_cacheKeyStem}-{id}"; return _myCache.Get<T>(cacheKey); } }
内容的提问来源于stack exchange,提问作者ewok
相关产品推荐
相关产品推荐

