Reset System.Lazy

In business class, I have:

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; } } } 

This works correctly, the user repository is called only when accessing the Manager property. Now I want to "reset" my manager property if ManagerId has changed. How to do it?

I can do:

  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; } } } 

Is there a cleaner way to do this? Isn't m_Manager.Reset() or something like this?

+27
May 11 '11 at 8:20
source share
2 answers

Lazy<T> does not define a Reset () method. What you implemented looks great, I think.

+15
May 11 '11 at 8:31
source share

If you are happy to use undocumented behavior and private fields, here is a way to do it:

 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); } 

And some test to use:

 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); 

EDIT: Deprecated! This solution no longer works as directed by Keith. We have our own owr ResetLazy in Signum Framework

 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; } } } 
+8
Jun 06 2018-11-06T00:
source share



All Articles