Работа для размышления? - PullRequest
1 голос
/ 30 апреля 2009

Привет!

У меня есть класс, который используется как кеш:

public sealed class MyCache<T> : IDisposable
{
    private ReaderWriterLockSlim theLock = new ReaderWriterLockSlim();
    private Dictionary<int, T> theCache = new Dictionary<int, T>();

    public void Add(int key, T value)
    {
        // ... logic/code to add to the dictionary
    }

    public void Clear()
    {
        theLock.EnterWriteLock();
        try
        {
            theCache.Clear();
        }
        finally
        {
            theLock.ExitWriteLock();
        }
    }
}

Этот кеш используется много раз, поэтому часто бывает несколько раз его в любой момент времени.

Пример 1:

public static class SpecialPageCache
{
    public static MyCache<string> SpecialPage = new MyCache<string>();
}

Пример 2:

public static class DdListCache
{
    public static MyCache<List<int, string>> DdlList = new MyCache<List<int, string>>();
}

и т. Д.

У меня есть служба, которая может очищать кеши по требованию, но, к сожалению, каждый из них должен очищаться следующим образом:

private void ClearThemAll()
{
    SpecialPageCache.SpecialPage.Clear();
    DdListCache.DdlList.Clear();
    // repeat for all other caches that may exist ...
}

Как я могу использовать отражение (или что-то еще?) Для вызова метода Clear () каждого кэша без необходимости явно делать это для каждого, как я делаю в вышеупомянутом методе ClearThemAll ()?

Ответы [ 7 ]

3 голосов
/ 30 апреля 2009
public interface ICache : IDisposable
{
    void Clear();
}

public interface ICache<T> : ICache
{
}

public abstract class CacheBase<T> : ICache<T>
{

}

public sealed class SpecialPageCache : CacheBase<string>
{
    internal SpecialPageCache()
    {
    }

}

public static class CacheFactory
{
    private static List<ICache> cacheList = new List<ICache>();

    public static TCache Create<TCache>()
        where TCache : ICache, new()
    {
        var result = new TCache();
        cacheList.Add(result);
        return result;
    }

    public static void ClearAll()
    {
        cacheList.ForEach((c) => c.Clear());
    }
}
3 голосов
/ 30 апреля 2009

Ик. Вам нужно будет просмотреть все типы в интересующей вас сборке и проверить все статические поля. Это сделано еще интереснее, потому что это универсальный тип. Ваша жизнь будет проще, если у вас есть неуниверсальный базовый класс:

public abstract class MyCache : IDisposable
{
    public abstract void Clear();
}

public sealed class MyCache<T> : MyCache
{
    // ...
}

Тогда, по крайней мере, относительно легко определить, является ли тип определенного поля MyCache, извлечь его значение и вызвать Clear, не возражая против отражения общих типов.

Это, как правило, неприятная проблема - вы уверены, что хотите очистить все кэши, подобные этой, без «понимания», какие кэши вы очищаете?

1 голос
/ 30 апреля 2009

Почему вам нужно специально очистить их, если они используют ресурсы, которые должны быть освобождены?

Мне интересно, не могли бы вы использовать System.WeakReference, чтобы кеш собирался как и когда?

http://msdn.microsoft.com/en-us/library/system.weakreference.aspx

1 голос
/ 30 апреля 2009

Отражение звучит противно. Не зная больше о времени жизни вашего объекта, сработает ли следующее?

public abstract class MyCacheBase : IDisposable {
    public static List<MyCache> caches = new List<MyCache>();

    public MyCacheBase() {
        caches.Add(this); // Add all constructed caches to the list
    }

    public static void ClearAllCaches() {
        foreach (MyCache cache in cache) // clear all constructed
            cache.Clear();               // caches in the list.
    }

    public void Finalize() {
        Dispose();
    }

    public void Dispose() {
        caches.Remove(this);  // Remove disposed classes from the list
    }

    public abstract void Clear();
}

public sealed class MyCache<T> : MyCacheBase
{
    // Rest of the implementation
}

(Спасибо Джону за то, что он отметил универсальность. Почти пропустил это.)

Если вы хотите иметь что-то вроде пользовательских кэшей, вы можете добавить пользовательский CacheFactory, который будет отслеживать кэши, созданные через него, а его метод ClearAll () будет очищать только эти кэши.

1 голос
/ 30 апреля 2009

Вы можете хранить ссылки на все ваши экземпляры кэшей в списке. Затем выполните итерацию того же списка и вызовите Clear для каждого MyCache. =) * * Тысяча одна

0 голосов
/ 30 апреля 2009

Если вы действительно хотите сделать рефлексию, вы бы сделали что-то вроде этого:

List<object> caches;
foreach (object obj in caches)
{
    Type t = obj.GetType();
    MethodInfo m = t.GetMethod("Clear");

    // Object does not have a public instance method named "Clear"
    if (m == null) { continue; }

    m.Invoke(obj, new object[0]);
}
0 голосов
/ 30 апреля 2009

Этот звук действительно знаком тому, как работают контейнеры Inversion of Control. Почему бы просто не иметь что-то вроде

Dictionary<Type, Dictionary<int, object>>

Затем все функции принимают тип T и затем используют этот тип для поиска подходящего словаря. Один статический MyCache может обрабатывать весь ваш тип, и его можно удалить одним вызовом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...