如果是能简单解决的问题,就不用想得太复杂了
2009-09-05 17:41 by 老赵, 7026 visits有个朋友在MSN问我说,有没有关于Emit的资料,它想生成一个类的动态代理。他抱怨Emit还是很麻烦,不过交谈过后知道他是想要做什么。他希望为一个对象的某个属性作延迟加载,这样可以避免一些无谓的消耗。例如:
public class SomeClass { public int SomeID { get; set; } // some other members... }
原本构造一个SomeClass时可以这样:
var someClass = new SomeClass(); someClass.SomeID = GetSomeID(); Process(someClass);
但是由于Process方法中可能不需要用到SomeID属性,于是在外部调用的GetSomeID方法可能就形成了无谓的性能损耗。一个常见的做法方式可能就是进行延迟加载了。那位朋友的意思是先把SomeID标为virtual:
public class SomeClass { public virtual int SomeID { get; set; } // some other members... }
然后使用Emit来生成一个动态类型,继承SomeClass,override掉SomeID属性,形成延迟加载。不过我提出,这个方法是不是太重了,因为动态代理不是那么孤立存在的,它往往需要考虑很多其他东西。例如缓存动态类型,例如,对于相同类型一个成员或多个成员的延迟加载,使生成一个通用的动态类型,还是多个动态类型。例如……怎么样的API是最合适的?
所以,如果只是简单的情况下,不如直接手动来实现这样的延迟效果:
public class LazySomeClass : SomeClass { public override int SomeID { get { return this.LazySomeID.Value; } set { this.LazySomeID.Value = value; } } public Lazy<int> LazySomeID { get; set; } }
于是在使用的时候就可以:
var someClass = new LazySomeClass(); someClass.LazySomeID = new Lazy<int>(() => GetSomeID()); Process(someClass);
这样其实就可以在一定程度上达到目的了。Lazy类的原理在之前也有过提及(这里需要些修改),这是一种简单但有用的类型。其实在项目的许多情况下,我们这么做也足够了。不需要复杂的方法,不需要复杂的Emit。不过如果您是为了锻炼能力,或者由于项目中此类需求特别多,想设计一个通用的的类库,这也不错。
当然,上面的实现也有缺陷,因为它不是最理想、最完整、最通用的延迟加载代理类(为什么?)。如果您感兴趣,也可以想象一个完美的代理类应该是什么样子的,甚至给出一个通用的辅助类库。
哦,对了,NHibernate的做法其实也不完美,有机会我会分析一下,并阐述我的看法的。
为了一个属性的延迟加载,动用Emit,太不划算了。