2010-10-27 115 views
63

在C#中,C#惰性加载自动属性

有没有办法将一个自动属性变成带有指定默认值的延迟加载自动属性?

从本质上讲,我试图把这个...

private string _SomeVariable 

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

      return _SomeVariable; 
    } 
} 

到不同的东西,在那里我可以指定默认的,它会自动处理剩下的...

[SetUsing(SomeClass.IOnlyWantToCallYouOnce())] 
public string SomeVariable {get; private set;} 
+0

@Gabe:注意,只有当它永远不会ret urns null。 – RedFilter 2010-10-27 19:25:16

+0

我发现...它似乎是使用单例模式 – ctorx 2010-10-28 19:50:08

回答

80

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

但是你可以使用4.0 Lazy<T>类型来创建这个模式

private Lazy<string> _someVariable =new Lazy<string>(SomeClass.IOnlyWantToCallYouOnce); 
public string SomeVariable { 
    get { return _someVariable.Value; } 
} 

此代码将懒洋洋地计算_someVariable首次Value表达被称为价值。它只会被计算一次,并将缓存价值以供将来使用Value属性

+1

实际上,它看起来像懒惰实现单例模式。这不是我的目标......我的目标是创建一个延迟加载的属性,该属性被懒惰地实例化,但随着它所在的类的实例一起被处理。懒惰似乎没有这样的表现。 – ctorx 2010-10-28 19:12:24

+12

@ctorx懒惰与单身模式无关。它正是你想要它做的。 – Stijn 2013-02-20 07:15:39

+4

请注意,在您的示例中,“SomeClass.IOnlyWantToCallYouOnce”必须是静态的,才能与字段初始值设定项一起使用。 – 2016-12-01 14:11:03

2

我不不认为这是纯粹的C#可能。但你可以使用IL重写器,如PostSharp。例如,它允许您根据属性在函数之前和之后添加处理程序。

5

不是这样,属性的参数必须是常数值,您不能调用代码(即使是静态代码)。

然而,您可能能够使用PostSharp的方面来实现某些功能。

检查出来:

PostSharp

17

也许是最简洁的,你可以得到的是使用空合并运算符:

get { return _SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce()); } 
+4

在'IOnlyWantToCallYouOnce'返回'null'的情况下,它会多次调用它。 – JaredPar 2010-10-27 19:26:08

+6

使用空合并运算符时,上述示例将失败。正确的语法是:'_SomeVariable ?? (_SomeVariable = SomeClass.IOnlyWantToCallYouOnce());' - 注意围绕设置'_SomeVariable'添加括号,如果它为空。 – 2012-10-22 16:49:51

4

下面是我实现的解决您的问题。基本上这个想法是一个属性,它将在第一次访问时由函数设置,随后的访问将产生与第一次访问相同的返回值。

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

    public T Value(Func<T> fn) 
    { 
     if (!_initialized) 
     { 
      _result = fn(); 
      _initialized = true; 
     } 
     return _result; 
    } 
} 

然后使用:

LazyProperty<Color> _eyeColor = new LazyProperty<Color>(); 
public Color EyeColor 
{ 
    get 
    { 
     return _eyeColor.Value(() => SomeCPUHungryMethod()); 
    } 
} 

当然还有各地的传递函数指针的开销,但它的工作,我和比我跑没有注意到的开销太大该方法一遍又一遍。

+0

将该函数赋予构造函数会更有意义吗?这样你就不会每次都以内联的方式创建它,而且你可以在第一次使用它之后进行处置。 – 2014-01-15 02:57:08

+0

@ lund.mikkel是的,那也可以。可能是两种方法的用例。 – deepee1 2014-01-15 17:07:49

+5

如果您将函数传递给构造函数,就像.Net的Lazy类一样,那么传入的函数必须是静态的,我知道这在许多情况下都不适合我的设计。 – crunchy 2014-05-09 18:16:25

8

有一个在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; } 
    } 
} 

目前可以写为:

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

    public string SomeVariable => _someVariable.Value; 
} 
+0

在上一节的代码,初始化实际上并不是懒惰的。在每次实例化类时,都会调用“IOnlyWantToCallYouOnce”。 – 2016-07-03 14:51:51

+0

@TomBlodget谢谢,你是对的 – 2016-08-18 14:56:47

+0

因此换句话说这不是懒加载? – Zapnologica 2017-01-30 08:40:39

0

https://github.com/bcuff/AutoLazy使用Fody到给你这样的东西

public class MyClass 
{ 
    // This would work as a method, e.g. GetSettings(), as well. 
    [Lazy] 
    public static Settings Settings 
    { 
     get 
     { 
      using (var fs = File.Open("settings.xml", FileMode.Open)) 
      { 
       var serializer = new XmlSerializer(typeof(Settings)); 
       return (Settings)serializer.Deserialize(fs); 
      } 
     } 
    } 

    [Lazy] 
    public static Settings GetSettingsFile(string fileName) 
    { 
     using (var fs = File.Open(fileName, FileMode.Open)) 
     { 
      var serializer = new XmlSerializer(typeof(Settings)); 
      return (Settings)serializer.Deserialize(fs); 
     } 
    } 
}