重置System.Lazy

时间:2011-05-11 08:20:41

标签: c#-4.0

在商务舱中,我有:

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

这样做正常,只有在访问Manager属性时才会调用自定义存储库。 现在我想在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()或类似的东西?

3 个答案:

答案 0 :(得分:17)

Lazy<T>未定义Reset()方法。你认为你实施的内容看起来很好。

答案 1 :(得分:10)

如果您对使用未记录的行为和私有字段感到满意,可以使用以下方法:

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 Framework中构建了owr自己的ResetLazy

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

答案 2 :(得分:0)

在重新设置Lazy之前,您还可以添加一个条件,只有在它被初始化时才会重置“if(m_Manager.IsValueCreated)”。