如何强制Lazy <t>对象创建/重新创建值?</t>

时间:2011-02-04 11:18:49

标签: asp.net-mvc c#-4.0 lazy-evaluation

我试着懒惰&lt;选择列表&gt;用于在我的ASP.NET MVC项目中延迟缓存任何查找数据。但是我无法强制Lazy对象在更改时重新加载查找数据。

我创建派生类,如下面的代码。我发现懒惰&lt; T>使用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值始终为false。

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

1 个答案:

答案 0 :(得分:10)

经过几个小时的搜索&amp;测试,我认为不可能重置懒惰对象的状态。但我可以创建包装来处理这个问题。包装类包含惰性对象和创建新惰性对象的必要对象。代码应该是这样的。

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);
        };
    }
}

上面的代码允许我们重置对象的状态以强制它为已定义的函数检索新数据。

之后,我尝试使用上面的方法来缓存ASP.NET MVC中的SelectList对象。但它总是从数据库中检索新的,因为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