我这个技术博客被冷落了近1年之后,我觉得不能再这样下去,至少应该平均2周发一篇博文。坚持了两三篇博文之后,我觉得今天是应该写点什么了,却发现这段时间以来似乎没什么值得摆出来的,仔细回想了一遍,大概就只有Lazy<T>还有点意思,可以写写。
Lazy<T>,正如其名,是为懒人设计的一个懒加载处理类。所谓懒加载,最简单的实现就是事先申明变量,但在实际使用的时候才创建对象实例。比如,通常会这么写一个懒加载的属性:
private IList<string> names; public IList<string> { get { return names ?? (names == new List<string>()); } }
懒加载比较典型的例子就是实现Singleton模式了。简单的Singleton通常会这样写:
public class Singleton1 { private static Singleton1 instance; public static Singleton1 Default { get { return instance ?? (instance = new Singleton1()); } } private Singleton1() { } }
改写成Lazy<T>实现
public class Singleton2 { private static readonly Lazy<Singleton2> lazyInstance = new Lazy<Singleton2>(); public static Singleton2 Default { get { return lazyInstance.Value; } } }
不过上面这个例子不是真正的单例,使用Lazy<T>的默认构造产生懒加载实例,需要T类型有公共的默认构造,否则在运行时会抛出 System.MissingMemberException。所以单例里其实应该用
Lazy<T>(Func<T>)
所以再改写
public class Singleton3 { private static readonly Lazy<Singleton3> lazyInstance = new Lazy<Singleton3>(Create); public static Singleton3 Default { get { return lazyInstance.Value; } } private static Singleton3 Create() { return new Singleton3(); } private Singleton3() { } }
这么看来,Lazy<T>实现的代码貌似更多,没能偷到懒……不过,如果要求线程安全的Singleton呢,一般会这么实现:
public class Singleton4 { private static Singleton4 instance; private static readonly object locker = new object(); public static Singleton4 Default { get { if (instance == null) { lock (locker) { if (instance == null) { instance = new Singleton4(); } } } return instance; } } private Singleton4() { } }
这段代码,又是锁又是判断的,光“instance == null”就判断了两次,为什么?想不明白就Google,再搞不懂就看个没这么复杂的实现
public class Singleton5 { private static readonly Lazy<Singleton5> lazyInstance = new Lazy<Singleton5>(Create, true); public static Singleton5 Default { get { return lazyInstance.Value; } } private static Singleton5 Create() { return new Singleton5(); } private Singleton5() { } }
也就是说,从线程不安全到线程安全,只换了个Lazy<T>的构造方法,多加了一个布尔参数就解决了——简单方便。Lazy<T>提供了6个构造方法,它的文档已经写得很清楚,就不多说了。
还要说明的一点是,懒加载当然不只是为了Singleton而设计的,就拿本文中的第一个例子来说,它有可能会有更复杂也更实际一点的实现(需要的时候再从数据库去获取数据):
class Blabla { private readonly Lazy<IList<string>> lazyNames; public Blabla() { lazyNames = new Lazy<IList<string>>(GetNameList); } private IList<string> GetNameList() { DataTable data = dbHelper.getUsers(); List<string> names = new List<string>(); foreach (DataRow row in data.Rows) { names.Add(row["name"].ToString()); } return names; } public IList<string> Names { get { return lazyNames.Value; } } }
本文出自 “边城客栈 学海无涯” 博客,请务必保留此出处http://jamesfancy.blog.51cto.com/2516291/1365402
懒人懒类懒方法 - System.Lazy<T>,布布扣,bubuko.com
原文:http://jamesfancy.blog.51cto.com/2516291/1365402