Сбросить System.Lazy - PullRequest
       3

Сбросить System.Lazy

35 голосов
/ 11 мая 2011

В бизнес-классе у меня есть:

 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 ]

17 голосов
/ 11 мая 2011

Lazy<T> не определяет метод Reset ().То, что вы реализовали, выглядит хорошо, я думаю.

10 голосов
/ 06 июня 2011

Если вы довольны использованием недокументированного поведения и личных полей, вот способ сделать это:

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

РЕДАКТИРОВАТЬ: устарело! Это решение больше не работает, как указано Китом. Мы создали собственный ResetLazy в 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;
        }
    }
}
0 голосов
/ 09 апреля 2018

Перед повторным созданием Lazy вы также можете добавить условие сброса, только если оно было инициализировано "if (m_Manager.IsValueCreated)".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...