代码之家  ›  专栏  ›  技术社区  ›  Dirk Boer

用C编写延迟加载属性的简洁方法#

  •  2
  • Dirk Boer  · 技术社区  · 6 年前

    当我想利用 Lazy<T> 需要参考 this 我需要写很多样板代码:

    // the private member
    private Lazy<SubEventCollection> _SubEvents;
    
    public Event()
    {
        // needs to be initialized in the constructor because I refer to this
        _SubEvents = new Lazy<SubEventCollection3>(CreateSubEvents);
    }
    
    // the "core" body
    private SubEventCollection CreateSubEvents()
    {
        SubEventCollection3 collection;
    
        using ( var stream = new MemoryStream(DbSubEventsBucket) )
            collection = Serializer.Deserialize<SubEventCollection3>(stream);
    
        collection.Initialize(this);
    
        return collection;
    }
    
    // The final property
    public SubEventCollection SubEvents => _SubEvents.Value;
    

    这真的有必要吗?这感觉像是太多的样板和所有的地方。有没有什么捷径可以读得好一点,周围没有那么多单独的样板文件? 很多

    我更喜欢的方式是类似Knockout.js/TypeScript的东西。

    subEvents = ko.lazyComputed(() =>
    {
        SubEventCollection3 sub_events;
    
        using ( var stream = new MemoryStream(DbSubEventsBucket) )
            sub_events = Serializer.Deserialize<SubEventCollection3>(stream);
    
        sub_events.Initialize(this);
    
        return sub_events;
    })
    

    这里没有太多的“活动部件”,而且非常简洁。

    private SubEventCollection _SubEvents;
    
    public SubEventCollection SubEvents
    {
        get
        {
            if ( _SubEvents == null )
            {
                using ( var stream = new MemoryStream(DbSubEventsBucket) )
                    collection = Serializer.Deserialize<SubEventCollection3>(stream);
    
                collection.Initialize(this);
    
                _SubEvents = collection;
            }
    
            return _SubEvents;
        }
    }
    

    至少这比懒惰的方法有更少的“活动部分”,而且我可以把所有的东西放在一起(不必把一半的逻辑放在构造函数中)。当然,这还有很多其他的缺点,比如它不是线程安全的。

    附言

    2 回复  |  直到 6 年前
        1
  •  0
  •   TheHans255    6 年前

    我建议搬家 Lazy 从类的内部到类在方法中的使用方式。急切地初始化 Event 在类的主体内(包括其 SubEventCollection ),而不是使用 事件 除此之外,使用 Lazy<Event> .

    public class Event 
    {
        public SubEventCollection SubEvents { get; private set; }
        public Event()
        {
             using ( var stream = new MemoryStream(DbSubEventsBucket) )
                 SubEvents = Serializer.Deserialize<SubEventCollection3>(stream);
    
             SubEvents.Initialize(this);
        }
    }
    

    但是后来,不是返回一个 从产生事件的内容中,返回 ,使他们能够根据需要返回更多数据。这样做还有一个好处,就是通知用户 事件 获取事件数据是一项潜在的昂贵操作。

        2
  •  -1
  •   Dirk Boer    6 年前

    班级:

    /// <summary>
    /// Warning: might not be as performant (and safe?) as the Lazy<T>, see: 
    /// https://codereview.stackexchange.com/questions/207708/own-implementation-of-lazyt-object
    /// </summary>
    public class MyLazy<T>
    {
        private T               _Value;
        private volatile bool   _Loaded;
        private object          _Lock = new object();
    
    
        public T Get(Func<T> create)
        {
            if ( !_Loaded )
            {
                lock (_Lock)
                {
                    if ( !_Loaded ) // double checked lock
                    {
                        _Value   = create();
                        _Loaded = true;
                    }
                }
            }
    
            return _Value;
        } 
    
    
        public void Invalidate()
        {
            lock ( _Lock )
                _Loaded = false;
        }
    }
    

    MyLazy _SubEvents = new MyLazy();
    public SubEventCollection SubEvents => _SubEvents.Get(LoadSubEvents);
    
    private SubEventCollection LoadSubEvents()
    {
        using ( var stream = new MemoryStream(DbSubEventsBucket) )
        {
            var sub_event_collection = Serializer.Deserialize<SubEventCollection>(stream);
            sub_event_collection.Initialize(this);
    
            return sub_event_collection;
        }
    }
    

    优势:

    • 我可以把所有相关的代码放在一起(不必把一半放在构造函数中)