繁体   English   中英

在 C# 中从其接口的泛型类型存储和访问类的实现特定数据

[英]storing and accessing implementation specific data of a class from generic type of its interface in c#

我正在尝试编写一个通用缓存存储库,为正在缓存的每个数据类型添加一个基本键。

    public interface ICacheModel
    {
        private static readonly string _baseKey;
        public static string GetBaseCacheKey()
        {
            return _baseKey;
        }
    }
    public interface ICacheRepository<T> where T : class, ICacheModel
    {
        Task<T> GetAsync(string key);
    }
    public class CacheRepository<T> : ICacheRepository<T> where T : class, ICacheModel
    {
        private readonly IDistributedCache _distributedCache;

        public CacheRepository(IDistributedCache distributedCache)
        {
            _distributedCache = distributedCache;
        }

        public async Task<T> GetAsync(string key)
        {
            var res = await _distributedCache.GetAsync<T>(T.GetBaseCacheKey() + key );
            return res;
        }
    }

然后我继承我计划从 ICacheModel 缓存的任何对象,并在我需要在我的项目中缓存的任何地方注入 ICacheRepository。

但由于编译器错误 CS0119,我无法访问静态方法GetBaseCacheKey()

关于如何拥有此功能的任何想法?

更新:


    public class CacheSampleClass : ICacheModel
    {
        public Guid Id { get; set; }
        public string Prop1 { get; set; }
        public string Prop2 { get; set; }

        private static readonly string _baseKey = "CacheSampleClass-";
        public static string GetBaseCacheKey()
        {
            return _baseKey;
        }
    }

这是我要缓存的继承类的示例。 我希望 GetBaseCacheKey 在由 CacheSampleClass 制作的所有对象中是唯一的,并且与由继承 ICacheModel 的其他类制作的所有对象不同

最简单的解决方案可能是使用反射来获取类名作为“baseCacheKey”。

_distributedCache.GetAsync<T>(typeof(T).FullName  + key );

另一种解决方案是将基本键定义为缓存对象的参数,而不是类型:

public CacheRepository(IDistributedCache distributedCache, string baseKey) 
...

第三种解决方案是在接口中定义一个属性:

public interface ICacheModel
{
        public string BaseKey {get;}
}

所述接口的实现可以只提供返回常量或文字值的 get 方法的实现,因此没有任何针对每个对象的字段。 但是该属性不能像发布的示例中那样是静态的。

每种选择都有一些优点和缺点,因此这取决于您想要做什么。

接口中的静态成员是在 C# 8.0 中引入的,我建议您避免使用它们,因为接口通常应该将实现(字段)与合同(方法或属性)断开连接。

在您的情况下,最好转换为常规财产

public interface ICacheModel
{
   string GetBaseCacheKey();
}

并将使用静态字段的实现移动到实现您的接口的类

不能实现静态接口方法; 静态成员只属于它们的声明类型。

你可以这样做:

public interface ICacheModelKeyProvider<T> where T : class
{
    string BaseKey { get; }
}

然后在您的存储库中:

public class CacheRepository<T> : ICacheRepository<T> where T : class
{
    private readonly IDistributedCache distributedCache;
    private readonly ICacheModelKeyProvider<T> keyProvider;

    public CacheRepository(
        IDistributedCache distributedCache,
        ICacheModelKeyProvider<T> keyProvider)
    {
        this.distributedCache = distributedCache;
        this.keyProvider = keyProvider;
    }

    public async Task<T> GetAsync(string key)
    {
        var res = await _distributedCache.GetAsync<T>(keyProvider.BaseKey + key);
        return res;
    }
}

然后,您创建的每个模型类型都需要一个ICacheModelKeyProvider然后才能拥有存储库。

例如

public class CacheSampleClass
{
    public Guid Id { get; set; }
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }
}

public class CacheSampleClassKeyProvider : ICacheModelKeyProvider<CacheSampleClass>
{
    public string BaseKey { get; } = "CacheSampleClass-"; 
}

或者,如果您想要默认行为,您甚至可以拥有一个通用提供程序:

public class DefaultKeyProvider<T> : ICacheModelKeyProvider<T>
{
    public string BaseKey { get; } = $"{typeof(T).Name}-"; 
}

如果感觉更整洁,您甚至可以嵌套该类:

public class CacheSampleClass
{
    public Guid Id { get; set; }
    public string Prop1 { get; set; }
    public string Prop2 { get; set; }

    public class KeyProvider : DefaultKeyProvider<CacheSampleClass> { }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM