翔如菲菲

其实天很蓝,阴云总会散;其实海不宽,此岸连彼岸.

导航

较为理想的延迟代理的编写方式

之前我谈到,在普通情况下我们可以很轻松地写出过一个代理类,用来处理延迟加载的情况。当时给出了一个很简单的做法,也就是指创建基类,覆盖它的一些属性实现,类似这种:

public class LazySomeClass : SomeClass
{
public override int SomeID
{
get
{
return this.LazySomeID.Value;
}
set
{
this.LazySomeID.Value = value;
}
}

public Lazy<int> LazySomeID { get; set; }
}

不过我当时也提到,这么做可能够用,但是也有一些缺点。例如,它破坏了SomeID属性中包含的业务逻辑。可能SomeID原本会包含一些验证逻辑,或和另外一个属性加以同步,或发起INotifyPropertyChanging/Changed中的事件。

因此我又想了想,理想中的延迟加载方式应该是什么样的呢?例如,同样是个SomeClass类,其中部分属性允许“设置”延迟加载:

public class SomeClass
{
public SomeClass() { }

public SomeClass(int i) { }

public virtual int LazyInt { get; set; }

public virtual bool LazyBoolean { get; set; }

public int EagerInt { get; set; }

public bool EagerBoolean { get; set; }

// some other members...
}

如果是一个较为合理的延迟代理类,我认为它的写法应该是这样的:

public class LazySomeClass : SomeClass
{
public override int LazyInt
{
get
{
if (!this.m_lazyIntLoaded)
{
if (this.m_lazyIntLoader != null)
{
base.LazyInt = this.m_lazyIntLoader();
this.m_lazyIntLoader = null;
}

this.m_lazyIntLoaded = true;
}

return base.LazyInt;
}
set
{
base.LazyInt = value;
this.m_lazyIntLoaded = true;
this.m_lazyIntLoader = null;
}
}

private bool m_lazyIntLoaded = false;
private Func<int> m_lazyIntLoader = null;
public Func<int> LazyIntLoader
{
get
{
return this.m_lazyIntLoader;
}
set
{
this.m_lazyIntLoader = value;
this.m_lazyIntLoaded = false;
}
}
}

如果我们需要为LazyInt属性设置延迟加载,那么可以设置LazyIntLoader属性,它是一个Func<int>委托对象。这种实现方式看上去复杂,不过它有一定的合理性:

  1. 每个Loader只执行一次,直到提供新的Loader。
  2. Loader执行后,会赋值给base.LazyInt,保持基类的业务逻辑。
  3. 从base.LazyInt读取,同样保持基类的业务逻辑。
  4. 如果不需要延迟加载,那么属性的行为保持不变。

其中第4点非常重要,这意味着这是一种可以“标准化”的延迟加载代理类的标准写法。我们可以在运行时使用Emit生成新的类型,继承目标类,为每个 virtual属性在子类中重写一份。由于在默认情况下属性的行为不会改变,因此这样的代理类不会有问题。甚至,“辅助类库”的接口我也想好了:

var builder = LazyFactory.Create(() => new SomeClass(10)
{
EagerInt = 10,
EagerBoolean = true
});

SomeClass value = builder
.Setup(c => c.LazyInt, () => GetLazyValue<int>())
.Setup(c => c.LazyBoolean, () => GetLazyValue<bool>())
.Create();

您有兴趣实现一下吗?

Ivony的精彩回复:

public class LazyLoader<T>
    {

        private Func<T> _loader;
        private T _value;
        private bool _loaded;

        public LazyLoader(Func<T> loader)
        {
            _loader = loader;
        }

        public T GetValue()
        {
            if (!_loaded)
                _value = _loader();

            return _value;
        }

        public static implicit operator T(LazyLoader<T> loader)
        {

            if (loader == null)
                return default(T);

            return loader.GetValue();
        }

        public static implicit operator LazyLoader<T>(T value)
        {
            var loader = new LazyLoader<T>(null);
            loader._value = value;
            loader._loaded = true;
            return loader;
        }

        public static implicit operator LazyLoader<T>(Func<T> loader)
        {
            return new LazyLoader<T>(loader);
        }
    }
 

原文URL:http://www.cnblogs.com/JeffreyZhao/archive/2009/09/07/standard-lazy-proxy.html

posted on 2011-03-12 11:03  翔如飞飞  阅读(186)  评论(0)    收藏  举报