Как заставить объект Lazy <T>создать / заново создать значение? - PullRequest
10 голосов
/ 04 февраля 2011

Я пытаюсь Lazy для ленивого кэширования любых данных поиска в моем проекте ASP.NET MVC.Но я не могу заставить объект Lazy перезагружать данные поиска при их изменении.

Я создаю производный класс, как показано в следующем коде.Я обнаружил, что Lazy использует свойство IsValueCreated для сохранения текущего состояния.Однако в методе MappingFunc я не могу изменить значение IsValueCreated, потому что это статический метод.

public class LazySelectList : Lazy<SelectList>
{
    public LazySelectList(Func<LimeEntities, IEnumerable> initFn, string dataValueField, string dataTextField)
        : base(MapingFunc(initFn, dataValueField, dataTextField))
    {
    }

    public new bool IsValueCreated { get; set; }

    public static Func<SelectList> MapingFunc(Func<DbContext, IEnumerable> valueFactory, string dataValueField, string dataTextField)
    {
        return () =>
        {
            var context = ObjectFactory.GetInstance<DbContext>();

            return new SelectList(valueFactory(context), dataValueField, dataTextField);
        };
    }
}

Я использую приведенный ниже код для вызова этой функции.Но это всегда создает новое значение, потому что значение IsValueCreated всегда ложно.

LookupCache.DocTypeList = new LazySelectList(db => db.DocTypes.OrderBy(x => x.Name), "ID", "Name");

1 Ответ

10 голосов
/ 06 февраля 2011

После нескольких часов поиска и тестирования, я думаю, что невозможно сбросить состояние ленивого объекта. Но я могу создать оболочку для решения этой проблемы. Класс-обертка содержит ленивый объект и необходимый объект для создания нового ленивого объекта. Код должен быть таким.

public class LazyCache<TSource, TModel> : IValue<TModel>
{
    private Lazy<TModel> _lazyObj;
    private readonly Func<TSource, TModel> _valueFactory;

    protected LazyCache()
    {
        Reset();
    }

    public LazyCache(Func<TSource, TModel> valueFactory) : this()
    {
        _valueFactory = valueFactory;
    }

    public void Reset()
    {
        _lazyObj = new Lazy<TModel>(MapingFunc());
    }

    public TModel Value
    {
        get { return _lazyObj.Value; }
    }

    protected virtual Func<TModel> MapingFunc()
    {
        return () =>
        {
            var context = ObjectFactory.GetInstance<TSource>();

            return _valueFactory(context);
        };
    }
}

Приведенный выше код позволяет нам сбросить состояние объекта, чтобы заставить его извлекать новые данные для определенной функции.

После этого я пытаюсь использовать вышеуказанный метод для кэширования объекта SelectList в ASP.NET MVC. Но он всегда извлекает новое из базы данных, потому что SelectList будет содержать объект IEnumerable вместо данных реального объекта. Итак, я решаю проблему, перечисляя данные в список временных объектов, как в следующем классе.

public class LazyList<TSource> : LazyCache<TSource, SelectList>
{
    private readonly Func<TSource, IEnumerable> _valueFactory;
    private readonly string _dataValueField;
    private readonly string _dataTextField;

    public LazyList(Func<TSource, IEnumerable> valueFactory, string dataValueField, string dataTextField)
    {
        _valueFactory = valueFactory;
        _dataValueField = dataValueField;
        _dataTextField = dataTextField;
    }

    protected override Func<SelectList> MapingFunc()
    {
        return () =>
        {
            var context = ObjectFactory.GetInstance<TSource>();

            //  Force to retrieve data from current IEnumerable to prevent lazy loading data that 
            //  cause system always connect to database every time they generate data from selectlist.
            var loop = _valueFactory(context).GetEnumerator();
            var tempList = new List<object>();

            while (loop.MoveNext())
            {
                tempList.Add(loop.Current);
            }

            return new SelectList(tempList, _dataValueField, _dataTextField);
        };
    }
}

PS. Весь исходный код является частью моей структуры Higgs RIA, доступной на веб-сайте Codeplex.

LazyCache.cs | LazyList.cs

...