以下是最常见的方案:
-
Lazy<Orders> 将 Orders 对象声明为延迟初始化,可以避免在不使用该对象的情况下浪费系统资源。
-
通过将不必要的对象的初始化延迟到已创建必要的对象之后,可以提高程序的启动性能。
Lazy<T> 及其相关的类型还支持线程安全,并提供一致的异常传播策略。
下表列出了 .NET Framework 版本 4 提供的、可在不同方案中启用延迟初始化的类型。
|
类型 |
说明 |
|---|---|
|
一个包装类,可为任意类库或用户定义的类型提供延迟初始化语义。 |
|
|
每个线程都可以访问自己的唯一值。 |
|
|
为对象的延迟初始化提供高级的 static(Visual Basic 中为 Shared)方法,此方法不需要类开销。 |
如果该类型没有默认的构造函数,则引发运行时异常。
对象包含一个 School 实例,但根据用户操作,可能不需要来自 School 对象的数据。
直接上Demo代码:
public class School { public string Name { get; set; } public string Address { get; set; } public School(string name, string address) { this.Name = name; this.Address = address; } }
public class Student { public string Number { get; set; } public string Name { get; set; } /// <summary> /// 学校对象,使用Lazy延迟加载School对象,当调用的时候才会初始化值 /// </summary> public Lazy<School> School = new Lazy<School>(() => new School("重庆工商大学", "重庆市南岸区")); public Student(string number, string name) { this.Name = name; this.Number = number; } }
class Program { static void Main(string[] args) { Student student = new Student("1001", "zhangfj");//声明并初始化Student对象 //首次,判断student对象的School属性值是否初始化 if (!student.School.IsValueCreated) { Console.WriteLine("School isn't Init"); } else { Console.WriteLine("School is Init"); } //使用student对象的School属性值 Console.WriteLine(student.School.Value.Name); //再次,判断student对象的School属性值是否初始化 if (!student.School.IsValueCreated) { Console.WriteLine("School isn't Init"); } else { Console.WriteLine("School is Init"); } Console.Read(); } }
因此,由哪个线程初始化对象并不重要,争用条件将是良性的。
Value 属性。
首先,修改Student的代码,使用延迟初始化实现School属性
public class Student { private Lazy<School> _school; public string Number { get; set; } public string Name { get; set; } /// <summary> /// 学校属性。当调用当前对象的School属性时候,才会初始化值。此处应用延迟初始化,对系统性能方面的提升很明显。 /// </summary> public School School { get { return this._school.Value; } } public Student(string number, string name) { this.Name = name; this.Number = number; //此处可以根据构造函数的参数,查询当前学生的学校信息等(实际开发中类似) this._school = new Lazy<School>(() => new School("重庆工商大学", "重庆市南岸区")); } }
class Program { static void Main(string[] args) { Student student = new Student("1001", "zhangfj");//声明并初始化Student对象 //首次,判断student对象的School属性值是否初始化 //if (!student.School.IsValueCreated) //{ // Console.WriteLine("School isn't Init"); //} //else //{ // Console.WriteLine("School is Init"); //} //使用student对象的School属性值 Console.WriteLine(student.School.Name); //再次,判断student对象的School属性值是否初始化 //if (!student.School.IsValueCreated) //{ // Console.WriteLine("School isn't Init"); //} //else //{ // Console.WriteLine("School is Init"); //} Console.Read(); } }
三、线程本地延迟初始化
例如,即使基本的初始化语句也将导致该变量只在访问它的第一个线程上进行初始化,如以下示例中所示。
[ThreadStatic] static int counter = 1;
counter 的线程都会将其起始值看作 1。
class Program { static void Main(string[] args) { // Initialize the integer to the managed thread id on a per-thread basis. ThreadLocal<int> threadLocalNumber = new ThreadLocal<int>(() => Thread.CurrentThread.ManagedThreadId); Thread t4 = new Thread(() => Console.WriteLine("threadLocalNumber on t4 = {0} ThreadID = {1}", threadLocalNumber.Value, Thread.CurrentThread.ManagedThreadId)); t4.Start(); Thread t5 = new Thread(() => Console.WriteLine("threadLocalNumber on t5 = {0} ThreadID = {1}", threadLocalNumber.Value, Thread.CurrentThread.ManagedThreadId)); t5.Start(); Thread t6 = new Thread(() => Console.WriteLine("threadLocalNumber on t6 = {0} ThreadID = {1}", threadLocalNumber.Value, Thread.CurrentThread.ManagedThreadId)); t6.Start(); // Ensure that thread IDs are not recycled if the // first thread completes before the last one starts. t4.Join(); t5.Join(); t6.Join(); /* Sample Output: threadLocalNumber on t4 = 14 ThreadID = 14 threadLocalNumber on t5 = 15 ThreadID = 15 threadLocalNumber on t6 = 16 ThreadID = 16 */ Console.Read(); }