简化C#

时间:2018-11-12 23:36:09

标签: c# syntax lazy-loading boilerplate

当我想使用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;
    }
}

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

我还缺少其他选择吗?

PS 我假设有两种不同的答案-一种用于真正的线程安全的延迟加载,另一种仅用于简洁的版本,在这种版本中,您不关心它是否被意外调用两次。

2 个答案:

答案 0 :(得分:0)

我建议将Lazy从类的内部转移到方法中如何使用该类。在类的主体(包括其Event)中初始化SubEventCollection,但不要在其外部使用Event,而应使用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);
    }
}

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

答案 1 :(得分:-1)

目前,我正在尝试自己的实现-仍然需要进行审查。

班级:

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

优势:

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