2011-05-11 27 views
28

在商務艙,我有:復位System.Lazy

class Employee{ 

     public Employee() { 
      m_Manager = new Lazy<Manager>(() => return myRepository.GetManager(ManagerId);); 
     } 
     public int ManagerId { get; set;} 
     private Lazy<Manager> m_Manager; 
     public Manager Manager { 
      get { 
       return m_Manager.Value; 
      } 
     } 
} 

這工作正常,自定義庫稱爲只有當訪問管理器屬性。 現在我想「重置」我的經理屬性,如果ManagerId更改。怎麼做 ?

我可以這樣做:

class Employee{ 

     public Employee() { 
      m_Manager = new Lazy<Manager>(() => return myRepository.GetManager(ManagerId);); 
     } 
     private int m_ManagerId; 
     public int ManagerId { 
      get { return m_ManagerId;} 
      set { 
       if(m_ManagerId != value) 
       { 
        m_ManagerId = value; 
        m_Manager = new Lazy<Manager>(() => return myRepository.GetManager(ManagerId);); 
       } 
      } 
     } 
     private Lazy<Manager> m_Manager; 
     public Manager Manager { 
      get { 
       return m_Manager.Value; 
      } 
     } 
} 

有一個更清潔的方式來做到這一點?是不是有m_Manager.Reset()或類似的東西?

回答

15

Lazy<T>沒有定義復位()方法。我認爲你已經實現了很好的一面。

8

如果你很高興與使用無證的行爲和私人領域,在這裏是做它的方法:

public static void ResetPublicationOnly<T>(this Lazy<T> lazy) 
{ 
    const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic; 

    LazyThreadSafetyMode mode = (LazyThreadSafetyMode)typeof(Lazy<T>).GetProperty("Mode", flags).GetValue(lazy, null); 
    if (mode != LazyThreadSafetyMode.PublicationOnly) 
     throw new InvalidOperationException("ResetPublicationOnly only works for Lazy<T> with LazyThreadSafetyMode.PublicationOnly"); 

    typeof(Lazy<T>).GetField("m_boxed", flags).SetValue(lazy, null); 
} 

而且一些試驗使用:

Lazy<string> val = new Lazy<string>(() => "hola" + DateTime.Now.Ticks, LazyThreadSafetyMode.PublicationOnly); 

val.ResetPublicationOnly(); //reset before initialized 
var str1 = val.Value; 
val.ResetPublicationOnly(); //reset after initialized 

var str2 = val.Value; 

Assert.AreNotEqual(str1, str2); 

編輯:棄用!該解決方案不再像Keith指出的那樣工作。我們在Signum的框架

public interface IResetLazy 
{ 
    void Reset(); 
    void Load(); 
    Type DeclaringType { get; } 
} 

[ComVisible(false)] 
[HostProtection(Action = SecurityAction.LinkDemand, Resources = HostProtectionResource.Synchronization | HostProtectionResource.SharedState)] 
public class ResetLazy<T>: IResetLazy 
{ 
    class Box 
    { 
     public Box(T value) 
     { 
      this.Value = value; 
     } 

     public readonly T Value; 
    } 

    public ResetLazy(Func<T> valueFactory, LazyThreadSafetyMode mode = LazyThreadSafetyMode.PublicationOnly, Type declaringType = null) 
    { 
     if (valueFactory == null) 
      throw new ArgumentNullException("valueFactory"); 

     this.mode = mode; 
     this.valueFactory = valueFactory; 
     this.declaringType = declaringType ?? valueFactory.Method.DeclaringType; 
    } 

    LazyThreadSafetyMode mode; 
    Func<T> valueFactory; 

    object syncLock = new object(); 

    Box box; 

    Type declaringType; 
    public Type DeclaringType 
    { 
     get { return declaringType; } 
    } 

    public T Value 
    { 
     get 
     { 
      var b1 = this.box; 
      if (b1 != null) 
       return b1.Value; 

      if (mode == LazyThreadSafetyMode.ExecutionAndPublication) 
      { 
       lock (syncLock) 
       { 
        var b2 = box; 
        if (b2 != null) 
         return b2.Value; 

        this.box = new Box(valueFactory()); 

        return box.Value; 
       } 
      } 

      else if (mode == LazyThreadSafetyMode.PublicationOnly) 
      { 
       var newValue = valueFactory(); 

       lock (syncLock) 
       { 
        var b2 = box; 
        if (b2 != null) 
         return b2.Value; 

        this.box = new Box(newValue); 

        return box.Value; 
       } 
      } 
      else 
      { 
       var b = new Box(valueFactory()); 
       this.box = b; 
       return b.Value; 
      } 
     } 
    } 


    public void Load() 
    { 
     var a = Value; 
    } 

    public bool IsValueCreated 
    { 
     get { return box != null; } 
    } 

    public void Reset() 
    { 
     if (mode != LazyThreadSafetyMode.None) 
     { 
      lock (syncLock) 
      { 
       this.box = null; 
      } 
     } 
     else 
     { 
      this.box = null; 
     } 
    } 
} 
+0

有點棘手,建立自己的OWR ResetLazy,但它可以被封裝成一種推廣方法,這可能非常簡化我的代碼。 THX – 2011-06-06 19:19:06

+1

希望你不是在緊密循環 – 2012-11-29 21:03:42

+2

看起來他們已經做了一些修改,以懶惰源代碼。這種方法不再起作用並且將引發異常 – Keith 2013-01-31 17:16:22