在 c# 中从其接口的泛型类型存储和访问 class 的实现特定数据
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;
}
}
这是我要缓存的继承 classes 的示例。
我希望 GetBaseCacheKey 在由 CacheSampleClass 生成的所有对象中是唯一的,并且不同于由继承 ICacheModel
的其他 class 生成的所有对象
最简单的解决方案可能是仅使用反射来获取 class 名称作为“baseCacheKey”。
_distributedCache.GetAsync<T>(typeof(T).FullName + key );
另一种解决方案是将基键定义为缓存对象的参数,而不是类型的参数:
public CacheRepository(IDistributedCache distributedCache, string baseKey)
...
第三种解决方案是在接口中定义一个属性:
public interface ICacheModel
{
public string BaseKey {get;}
}
所述接口的实现可以只提供 returns 常量或文字值的 get 方法的实现,因此没有任何针对此对象的字段。但是 属性 不能像发布的示例那样是静态的。
每种选择都有一些优点和缺点,所以这取决于你想做什么。
接口中的静态成员是在 C# 8.0 中引入的,我建议您避免使用它们,因为接口通常应该断开实现(字段)与契约(方法或 属性)的连接。
在你的情况下,最好转换为常规 属性
public interface ICacheModel
{
string GetBaseCacheKey();
}
并将使用静态字段的实现移动到实现您的接口
的class
不能实现静态接口方法;静态成员仅属于它们的声明类型。
您可以改为这样做:
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}-";
}
如果感觉更整洁,您甚至可以嵌套 class:
public class CacheSampleClass
{
public Guid Id { get; set; }
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public class KeyProvider : DefaultKeyProvider<CacheSampleClass> { }
}
我正在尝试编写一个通用的缓存存储库,为每个正在缓存的数据类型添加一个基本键。
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;
}
}
这是我要缓存的继承 classes 的示例。 我希望 GetBaseCacheKey 在由 CacheSampleClass 生成的所有对象中是唯一的,并且不同于由继承 ICacheModel
的其他 class 生成的所有对象最简单的解决方案可能是仅使用反射来获取 class 名称作为“baseCacheKey”。
_distributedCache.GetAsync<T>(typeof(T).FullName + key );
另一种解决方案是将基键定义为缓存对象的参数,而不是类型的参数:
public CacheRepository(IDistributedCache distributedCache, string baseKey)
...
第三种解决方案是在接口中定义一个属性:
public interface ICacheModel
{
public string BaseKey {get;}
}
所述接口的实现可以只提供 returns 常量或文字值的 get 方法的实现,因此没有任何针对此对象的字段。但是 属性 不能像发布的示例那样是静态的。
每种选择都有一些优点和缺点,所以这取决于你想做什么。
接口中的静态成员是在 C# 8.0 中引入的,我建议您避免使用它们,因为接口通常应该断开实现(字段)与契约(方法或 属性)的连接。
在你的情况下,最好转换为常规 属性
public interface ICacheModel
{
string GetBaseCacheKey();
}
并将使用静态字段的实现移动到实现您的接口
的class不能实现静态接口方法;静态成员仅属于它们的声明类型。
您可以改为这样做:
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}-";
}
如果感觉更整洁,您甚至可以嵌套 class:
public class CacheSampleClass
{
public Guid Id { get; set; }
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public class KeyProvider : DefaultKeyProvider<CacheSampleClass> { }
}