У меня есть абстрактный базовый класс, например:
public abstract class CacheValueProviderBase<T> where T : ICacheItem
{
protected ConcurrentDictionary<int,T> dataList = new ConcurrentDictionary<int, T>();
public virtual void Add(T model){ // add code }
public virtual bool Remove(int id){ //remove code }
public abstract string getName();
public abstract void UpdateForceFromDataBase();
public abstract void UpdateForceFromCacheServer();
public virtual bool allowForUpdater
{
get
{
return true;
}
}
public virtual bool beforeUpdate()
{
return true;
}
}
У меня есть несколько производных классов от этого абстрактного класса.Класс Slider_CacheValueProvider
, приведенный ниже, используется в качестве примера.
public class Slider_CacheValueProvider : CacheValueProviderBase<Cache_Home_Slider_Model>
{
public override string getName()
{
return "Slider_Cache";
}
public override void UpdateForceFromCacheServer()
{ // updating from cache server
}
public override void UpdateForceFromDataBase()
{ // updating from database
}
}
Модель кэша ползунка:
public class Cache_Home_Slider_Model : ICacheItemID
{
public int ID { get; set; }
public string SlideImage { get; set; }
public string Link { get; set; }
}
Все модели кэша зависят от свойства идентификатора и реализуют этот интерфейс только для упрощения операции переноса:
public interface ICacheItemID
{
int ID { get; set; }
}
Информация: мой механизм кэширования имеет 2 этапа.Первый шаг - внутренний кеш.Второй шаг - внешний кеш-сервер.
У меня есть обновление кеша.Периодически обновляется кеш, что зависит от свойства абстрактного класса 'allowForUpdater'.Во-первых, я нашел все производные классы с этим:
public static List<Type> CacheTypeList()
{
var type = typeof(CacheValueProviderBase<>);
return Assembly.GetExecutingAssembly().GetTypes().Where(i => !i.IsAbstract && !i.IsInterface &&
i.BaseType != null && i.BaseType.IsGenericType && i.BaseType.GetGenericTypeDefinition() == type
).ToList();
}
И итерацией так:
foreach (var item in CacheTypeList())
{
var cache= getCache(item);
if(cache.allowForUpdater && cache.beforeUpdate())
{
cache.UpdateForceFromCacheServer();
}
}
И метод getCache
:
public static CacheValueProviderBase<ICacheItem> getCache(Type type)
{
var val = storeList.Find(i => i.Key == type).Value;
return (CacheValueProviderBase<ICacheItem>)val;
}
storeListявляется статическим списком и включает глобальный Slider_CacheValueProvider в приложении.
Проблема заключается в методе getCache
.Когда я пытаюсь разыграть его, я получаю исключение.'Невозможно привести объект типа ...'.Slider_CacheValueProvider унаследован от базовой модели, а модель слайдера реализована от ICacheItem.В чем проблема?Почему я не могу разыграть?
Обновление 1:
Использование ключевого слова «out» для абстрагирования класса, получение этой ошибки: «Недопустимый модификатор дисперсии.В качестве варианта можно указать только параметры типа интерфейса и делегата.
Поэтому я изменяю абстрактный класс с помощью интерфейса.Интерфейс:
public interface ICacheProvider<T> where T : ICacheItemID
{
DateTime LastModifiedTime { get; set; }
void Add(T model);
bool Remove(int id);
bool Update(T model);
T Where(Func<T, bool> expression);
void Clear();
int Count(int id);
IEnumerable<T> GetList();
void AddList(IEnumerable<T> model);
void RemoveList(IEnumerable<int> model);
void RemoveByFunc(Func<KeyValuePair<int, T>, bool> expression);
IEnumerable<T> WhereList(Func<T, bool> expression);
string getName();
void UpdateForceFromDataBase(bool updateCache = true);
void UpdateForceFromCacheServer();
bool allowForUpdater { get; }
bool beforeUpdate();
}
И текущий абстрактный класс, подобный этому:
public abstract class CacheValueProviderBase<T> : ICacheProvider<T> where T : ICacheItemID
Если я меняю интерфейс на 'out T', получаю ошибку при Add, Update, AddList, RemoveByFunc.Ошибка:
"Недопустимая дисперсия, параметр типа 'T' должен быть противоположно допустимым для ICacheProvider.Add (T) (или другого имени метода)" T "является ковариантным."
Обновление 2:
Я изменил свой код.Я создал новый интерфейс для программы обновления следующим образом:
public interface ICacheUpdaterImplements
{
string getName();
void UpdateForceFromDataBase();
void UpdateForceFromCacheServer();
bool allowForUpdater();
}
Я получил этот интерфейс следующим образом:
public static ICacheUpdaterImplements getCacheUpdaterImplements(Type type)
{
return (ICacheUpdaterImplements)storeList.Single(i => i.Key == type).Value;
}
И изменил код программы обновления следующим образом:
foreach (var item in CacheTypeList())
{
var updater= getCacheUpdaterImplements(item);
if(updater.allowForUpdater())
{
updater.UpdateForceFromCacheServer();
}
}
Итак, я вижу, у меня неправильный дизайн.Я изменил код и решил проблему.