【问题标题】:coding style while accessing property for the first time and backing field member is null首次访问属性且支持字段成员为空时的编码样式
【发布时间】:2018-03-13 08:51:54
【问题描述】:

我正在寻找是否有优雅的方法来确保第一次访问属性时设置了关联的支持字段。例如,我最终使用以下代码范例来解决这个问题:

private Address _address;
        public Address Address
        {
            get
            {
                if (_address == null)
                {
                    _address = GetAddress();
                }return _address;
            }
        }  

【问题讨论】:

  • 请在标签中指定语言

标签: c# coding-style readability


【解决方案1】:

除非容易出错或耗时,否则我建议在构造函数中填充属性。否则,我建议使用Lazy<T> 来执行此操作,以确保线程安全:

public class MyClass
{
    private Address _address;

    public MyClass()
    {
        _address = GetAddress();
    }

    public Address Address {get {return _address;}}
}

使用Lazy<T>

public class MyClass
{
    private Lazy<Address> _address;

    public MyClass()
    {
        _address = new Lazy<Address>(() => GetAddress());
    }

    public Address Address {get {return _address.Value;}}
}

从 c#6 开始,你可以有这样一个自动实现的属性,但是你必须使 GetAddress() 方法 static

public Address Addgress {get;} = GetAddress();

这将转化为类似于我展示的第一个选项 - See SharpLab demo.

【讨论】:

    【解决方案2】:

    您可以使用一个简单的方法来稍微干燥一下属性代码:

    private T GetInstance<T>(ref T instance, Func<T> getInstance)
    {
        if (instance == null)
            instance = getInstance();
        return instance;
    }
    
    private Address _address;
    public Address Address => GetInstance<Address>(ref _address, () => GetAddress());
    
    private string _name;
    public string Name => GetInstance<string>(ref _name, () => GetName());
    

    编辑:在查看了 @Zohar 在 cmets 中友好指出的文章后,我希望使用 Lazy 是一种更好的方法,因为您可以获得具有良好性能的线程安全。因此,为了使其看起来尽可能整洁(IMO),可以这样做:

    private readonly Lazy<Address> _address = new Lazy<Address>(() => GetAddress());
    public Address Address => _address.Value;
    

    【讨论】:

    • 这不是线程安全的,而且与使用 Lazy 或自动实现的属性 public Address Addgress {get;} = GetAddress(); 相比,您在 c#6 中开箱即用。
    • 立即初始化属性。而这个答案是按需初始化的,这是拥有私有和公共的点。为什么这不是线程安全的?
    • 使用Lazy 也可以按需初始化。这不是线程保存,因为两个不同的线程都可以评估测试if (instance==null) 并发现它是true,然后都创建实例。进一步阅读 - Jon Skeet 的Implementing the Singleton Pattern in C#
    • 是的 Lazy 会按需初始化,但 { get; } = GetAddress(); 不会。这不太可能是线程安全的问题,因为它位于包含类的实例中。但它可以很容易地变成线程安全的静态方法。
    • 你改变了我的想法@Zohar。懒惰是要走的路,我可能会自己开始使用它。
    【解决方案3】:

    在构造函数本身中赋值属性值,像这样

    private Address _address;
    public Address Address
    {
      get { return _address; }
    }
    
    public ABC() //Constructor 
    {
      _address = GetAddress();
    }
    

    【讨论】:

    • 如果GetAddress() 是一种昂贵的方法,并且可能不会使用“地址”,那么我更喜欢 OP 的解决方案。
    • 但这就像我正在实例化一个对象并且可能根本无法访问该属性。在访问属性时这样做看起来有点懒惰初始化,不是吗?不确定这是否归结为一些代码气味..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-15
    • 2019-04-03
    • 2011-02-12
    相关资源
    最近更新 更多