注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Bioinformatics home

 
 
 

日志

 
 

.Net 4.0 延迟初始化:Lazy  

2010-05-28 08:18:54|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

   语言和模式互相促进,语言让模式实现有更多可能性,越来越多优秀的被语言实现.模式实现的责任从开发者转移到语言.延迟初始化(Lazyinitialization)已经在.Net 4.0中给出了默认实现.本文将探究其使用方法和实现.

  为什么要延迟初始化(Lazy initialization)?

    平时开发能接触到延迟初始化可能是在两个地方,一个是单件模式Singletonpattern,一个是Nhibernate;这两个典型场景很能说明为什么需要延迟初始化:

1.需要初始化的对象属于昂贵的资源,直到使用的时候再初始化load-on-demand

2.初始化过程本身相当复杂,代码中要避免这种无谓复杂性,直到使用再初始化

更多延迟初始化的资料,请点击这里;

.Net 4.0 Lazy<T>实现Lazy initialization

        .Net 4.0中的延迟初始化的默认实现时Lazy<T>,我们通过一个简单的例子看一下怎么使用,为了方便讨论我们新建一个Student的实体类:

    public class Student    {        public int ID        {            get;set;        }        public string Name        {            get; set;        }    } 延迟初始化Student:

 

  Lazy<Student> student = newLazy<Student>();  Console.WriteLine(student);  student.Value.ID = 23;  student.Value.Name = "New";  Console.WriteLine(student);  我们在Console.WriteLine(student);  一行设置断点查看,发现IsValueCreated是false ,Value值是null,截图如下:

 

继续往下走,在student.Value.ID = 23;赋值的时候,再次查看student对象的值,IsValueCreated为true,Value已经不为空,见下图.

  

我们可以猜想,应该是在Value的Get方法中对对象进行了实例化,打开Reflector v6验证:

Lazy
  1 [Serializable, DebuggerDisplay("ThreadSafetyMode={Mode}, IsValueCreated={IsValueCreated}, IsValueFaulted={IsValueFaulted}, Value={ValueForDebugDisplay}"), DebuggerTypeProxy(typeof(System_LazyDebugView<>)), ComVisible(false), HostProtection(SecurityAction.LinkDemand, Synchronization=true, ExternalThreading=true)]  2  public class Lazy<T>  3 {  4     // Fields  5      private volatile object m_boxed;  6     [NonSerialized]  7     private readonly object m_threadSafeObj;  8     [NonSerialized]  9     private Func<T> m_valueFactory; 10     private static Func<T> PUBLICATION_ONLY_OR_ALREADY_INITIALIZED; 11  12     // Methods 13      static Lazy() 14     { 15         Lazy<T>.PUBLICATION_ONLY_OR_ALREADY_INITIALIZED = delegate { 16             return default(T); 17         }; 18     } 19  20     [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] 21     public Lazy() : this(LazyThreadSafetyMode.ExecutionAndPublication) 22     { 23     } 24  25     public Lazy(bool isThreadSafe) : this(isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None) 26     { 27     } 28  29     [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] 30     public Lazy(Func<T> valueFactory) : this(valueFactory, LazyThreadSafetyMode.ExecutionAndPublication) 31     { 32     } 33  34     public Lazy(LazyThreadSafetyMode mode) 35     { 36         this.m_threadSafeObj = Lazy<T>.GetObjectFromMode(mode); 37     } 38  39     public Lazy(Func<T> valueFactory, bool isThreadSafe) : this(valueFactory, isThreadSafe ? LazyThreadSafetyMode.ExecutionAndPublication : LazyThreadSafetyMode.None) 40     { 41     } 42  43     public Lazy(Func<T> valueFactory, LazyThreadSafetyMode mode) 44     { 45         if (valueFactory == null) 46         { 47             throw new ArgumentNullException("valueFactory"); 48         } 49         this.m_threadSafeObj = Lazy<T>.GetObjectFromMode(mode); 50         this.m_valueFactory = valueFactory; 51     } 52  53     private Boxed<T> CreateValue() 54     { 55         Boxed<T> boxed = null; 56         LazyThreadSafetyMode mode = this.Mode; 57         if (this.m_valueFactory != null) 58         { 59             try 60             { 61                 if ((mode != LazyThreadSafetyMode.PublicationOnly) && (this.m_valueFactory == Lazy<T>.PUBLICATION_ONLY_OR_ALREADY_INITIALIZED)) 62                 { 63                     throw new InvalidOperationException(Environment.GetResourceString("Lazy_Value_RecursiveCallsToValue")); 64                 } 65                 Func<T> valueFactory = this.m_valueFactory; 66                 if (mode != LazyThreadSafetyMode.PublicationOnly) 67                 { 68                     this.m_valueFactory = Lazy<T>.PUBLICATION_ONLY_OR_ALREADY_INITIALIZED; 69                 } 70                 return new Boxed<T>(valueFactory()); 71             } 72             catch (Exception exception) 73             { 74                 if (mode != LazyThreadSafetyMode.PublicationOnly) 75                 { 76                     this.m_boxed = new LazyInternalExceptionHolder<T>(exception.PrepForRemoting()); 77                 } 78                 throw; 79             } 80         } 81         try 82         { 83             boxed = new Boxed<T>((T) Activator.CreateInstance(typeof(T))); 84         } 85         catch (MissingMethodException) 86         { 87             Exception ex = new MissingMemberException(Environment.GetResourceString("Lazy_CreateValue_NoParameterlessCtorForT")); 88             if (mode != LazyThreadSafetyMode.PublicationOnly) 89             { 90                 this.m_boxed = new LazyInternalExceptionHolder<T>(ex); 91             } 92             throw ex; 93         } 94         return boxed; 95     } 96  97     private static object GetObjectFromMode(LazyThreadSafetyMode mode) 98     { 99         if (mode == LazyThreadSafetyMode.ExecutionAndPublication)100         {101             return new object();102         }103         if (mode == LazyThreadSafetyMode.PublicationOnly)104         {105             return Lazy<T>.PUBLICATION_ONLY_OR_ALREADY_INITIALIZED;106         }107         if (mode != LazyThreadSafetyMode.None)108         {109             throw new ArgumentOutOfRangeException("mode", Environment.GetResourceString("Lazy_ctor_ModeInvalid"));110         }111         return null;112     }113 114     private T LazyInitValue()115     {116         Boxed<T> boxed = null;117         switch (this.Mode)118         {119             case LazyThreadSafetyMode.None:120                 boxed = this.CreateValue();121                 this.m_boxed = boxed;122                 break;123 124             case LazyThreadSafetyMode.PublicationOnly:125                 boxed = this.CreateValue();126                 if (Interlocked.CompareExchange(ref this.m_boxed, boxed, null) != null)127                 {128                     boxed = (Boxed<T>) this.m_boxed;129                 }130                 break;131 132             default:133             {134                 object obj2;135                 bool lockTaken = false;136                 try137                 {138                     Monitor.Enter(obj2 = this.m_threadSafeObj, ref lockTaken);139                     if (this.m_boxed == null)140                     {141                         boxed = this.CreateValue();142                         this.m_boxed = boxed;143                     }144                     else145                     {146                         boxed = this.m_boxed as Boxed<T>;147                         if (boxed == null)148                         {149                             LazyInternalExceptionHolder<T> holder = this.m_boxed as LazyInternalExceptionHolder<T>;150                             throw holder.m_exception;151                         }152                     }153                 }154                 finally155                 {156                     if (lockTaken)157                     {158                         Monitor.Exit(obj2);159                     }160                 }161                 break;162             }163         }164         return boxed.m_value;165     }166 167     [OnSerializing]168     private void OnSerializing(StreamingContext context)169     {170         T local1 = this.Value;171     }172 173     public override string ToString()174     {175         if (!this.IsValueCreated)176         {177             return Environment.GetResourceString("Lazy_ToString_ValueNotCreated");178         }179         return this.Value.ToString();180     }181 182     // Properties183      public bool IsValueCreated184     {185         [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]186         get187         {188             return ((this.m_boxed != null) && (this.m_boxed is Boxed<T>));189         }190     }191 192     internal bool IsValueFaulted193     {194         get195         {196             return (this.m_boxed is LazyInternalExceptionHolder<T>);197         }198     }199 200     internal LazyThreadSafetyMode Mode201     {202         get203         {204             if (this.m_threadSafeObj == null)205             {206                 return LazyThreadSafetyMode.None;207             }208             if (this.m_threadSafeObj == Lazy<T>.PUBLICATION_ONLY_OR_ALREADY_INITIALIZED)209             {210                 return LazyThreadSafetyMode.PublicationOnly;211             }212             return LazyThreadSafetyMode.ExecutionAndPublication;213         }214     }215 216     [DebuggerBrowsable(DebuggerBrowsableState.Never)]217     public T Value218     {219         get220         {221             Boxed<T> boxed = null;222             if (this.m_boxed != null)223             {224                 boxed = this.m_boxed as Boxed<T>;225                 if (boxed != null)226                 {227                     return boxed.m_value;228                 }229                 LazyInternal< type="text/javascript">< type="text/javascript">< type="text/javascript">< type="text/javascript">< type="text/javascript">ExceptionHolder<T> holder = this.m_boxed as LazyInternalExceptionHolder<T>;230                 throw holder.m_exception;231             }232             Debugger.NotifyOfCrossThreadDependency();233             return this.LazyInitValue();234         }235     }236 237     internal T ValueForDebugDisplay238     {239         get240         {241             if (!this.IsValueCreated)242             {243                 return default(T);244             }245             return ((Boxed<T>) this.m_boxed).m_value;246         }247     }248 249     // Nested Types250      [Serializable]251     private class Boxed252     {253         // Fields254          internal T m_value;255 256         // Methods257          [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]258         internal Boxed(T value)259         {260             this.m_value = value;261         }262     }263 264     private class LazyInternalExceptionHolder265     {266         // Fields267          internal Exception m_exception;268 269         // Methods270          [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]271         internal LazyInternalExceptionHolder(Exception ex)272         {273             this.m_exception = ex;274         }275     }276 }277 278  是不是和我们想的一样呢?

为了更清晰的看出延迟加载的处理逻辑,我按照这个代码的实现思路,去掉复杂应用场景中队异常,多线程等方面的代码,重新实现了一个Lazy<T>,就叫它YaLazy<T>吧

 1  public class YaLazy<T> 2     { 3         private bool _isValueCreated = false; 4         public bool IsValueCreated 5         { 6             get 7             { 8                 return _isValueCreated; 9             }10         }11         private T _value;12         public T Value13         {14             get15             {16                 if (this._value != null)17                 {18                     return (T)_value;19                 }20                 return CreateValue();21 22             }23         }24         private T CreateValue()25         {26             _isValueCreated = true;27             _value = (T)Activator.CreateInstance(typeof(T));28             return _value;29         }30     }使用方法和Lazy<T>类似:

1             YaLazy<Student> student2 = new YaLazy<Student>();2             Console.WriteLine(student2);3             student2.Value.ID = 23;4             student2.Value.Name = "New";5             Console.WriteLine(student2);6   建议单步调试~

Share |
< type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#username=ligaoren">

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ligaorenvip/archive/2010/05/25/5624093.aspx

  评论这张
 
阅读(1114)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017