C#Lazy Loaded自动属性

cto*_*orx 93 c# automatic-properties

在C#中,

有没有办法将自动属性转换为具有指定默认值的延迟加载自动属性?

基本上,我试图扭转这个......

private string _SomeVariable

public string SomeVariable
{
     get
     {
          if(_SomeVariable == null)
          {
             _SomeVariable = SomeClass.IOnlyWantToCallYouOnce();
          }

          return _SomeVariable;
     }
}
Run Code Online (Sandbox Code Playgroud)

到不同的东西,我可以指定默认值,它自动处理其余的...

[SetUsing(SomeClass.IOnlyWantToCallYouOnce())]
public string SomeVariable {get; private set;}
Run Code Online (Sandbox Code Playgroud)

Jar*_*Par 105

不,那里没有.自动实现的属性仅用于实现最基本的属性:带有getter和setter的后备字段.它不支持这种类型的自定义.

但是,您可以使用4.0 Lazy<T>类型来创建此模式

private Lazy<string> _someVariable =new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce);
public string SomeVariable => _someVariable.Value;
Run Code Online (Sandbox Code Playgroud)

此代码将懒惰地计算_someVariable第一次Value调用表达式时的值.它只会被计算一次,并将缓存该值以供将来使用该Value属性

  • @ctorx Lazy与单例模式无关.它完全符合您的要求. (14认同)
  • 注意,示例中的`SomeClass.IOnlyWantToCallYouOnce`必须是静态的才能与字段初始值设定项一起使用. (8认同)

Gab*_*art 34

您可以获得的最简洁的可能是使用null-coalescing运算符:

get { return _SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce()); }
Run Code Online (Sandbox Code Playgroud)

  • 在"IOnlyWantToCallYouOnce"返回"null"的情况下,它将多次调用它. (10认同)
  • 使用null-coalescing运算符时,上面的示例将失败.正确的语法是:`_SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce());` - 注意如果它为null,则在设置`_SomeVariable`周围添加括号. (9认同)

Ale*_*rck 14

C#6中有一个名为Expression Bodied Auto-Properties的新功能,它允许你把它写得更清洁:

public class SomeClass
{ 
   private Lazy<string> _someVariable = new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce);

   public string SomeVariable 
   {
      get { return _someVariable.Value; }
   }
}
Run Code Online (Sandbox Code Playgroud)

现在可以写成:

public class SomeClass
{
   private Lazy<string> _someVariable = new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce);

   public string SomeVariable => _someVariable.Value;
}
Run Code Online (Sandbox Code Playgroud)


cap*_*p29 11

运算符??=在 C# 8.0 及更高版本中可用,因此您现在可以更简洁地使用它:

private string _someVariable;

public string SomeVariable => _someVariable ??= SomeClass.IOnlyWantToCallYouOnce();

Run Code Online (Sandbox Code Playgroud)

  • 好的。请注意,它不像原始版本那样是线程安全的。通过一些开销,“Lazy&lt;T&gt;”在需要时提供内置安全性。 (2认同)

Are*_*ren 5

不是那样,属性的参数必须是值不变的,你不能调用代码(甚至是静态代码).

但是,您可以使用PostSharp的Aspects实现某些功能.

去看一下:

PostSharp


dee*_*ee1 5

这是我对你的问题的解决方案.基本上,这个想法是一个属性,它将在第一次访问时由函数设置,后续访问将产生与第一个相同的返回值.

public class LazyProperty<T>
{
    bool _initialized = false;
    T _result;

    public T Value(Func<T> fn)
    {
        if (!_initialized)
        {
            _result = fn();
            _initialized = true;
        }
        return _result;
    }
 }
Run Code Online (Sandbox Code Playgroud)

然后使用:

LazyProperty<Color> _eyeColor = new LazyProperty<Color>();
public Color EyeColor
{ 
    get 
    {
        return _eyeColor.Value(() => SomeCPUHungryMethod());
    } 
}
Run Code Online (Sandbox Code Playgroud)

当然有传递函数指针的开销,但是它为我完成了工作,而且与一遍又一遍地运行方法相比,我没有注意到太多的开销.

  • 如果你将函数传递给构造函数,就像.Net的Lazy类一样,那么传入的函数必须是静态的,我知道在很多情况下这不适合我的设计. (5认同)