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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 05:59:50