C# 缓存属性与惰性<;T>;
在.NET4中,还可以使用该类编写以下具有缓存属性的代码段。我测量了两种方法的性能,结果几乎相同。为什么我应该使用一个而不是另一个,这有什么真正的好处或魔力吗 缓存属性C# 缓存属性与惰性<;T>;,c#,.net,.net-4.0,lazy-loading,C#,.net,.net 4.0,Lazy Loading,在.NET4中,还可以使用该类编写以下具有缓存属性的代码段。我测量了两种方法的性能,结果几乎相同。为什么我应该使用一个而不是另一个,这有什么真正的好处或魔力吗 缓存属性 public static class Brushes { private static LinearGradientBrush _myBrush; public static LinearGradientBrush MyBrush { get {
public static class Brushes
{
private static LinearGradientBrush _myBrush;
public static LinearGradientBrush MyBrush
{
get
{
if (_myBrush == null)
{
var linearGradientBrush = new LinearGradientBrush { ...};
linearGradientBrush.GradientStops.Add( ... );
linearGradientBrush.GradientStops.Add( ... );
_myBrush = linearGradientBrush;
}
return _myBrush;
}
}
}
懒惰
public static class Brushes
{
private static LinearGradientBrush _myBrush;
public static LinearGradientBrush MyBrush
{
get
{
if (_myBrush == null)
{
var linearGradientBrush = new LinearGradientBrush { ...};
linearGradientBrush.GradientStops.Add( ... );
linearGradientBrush.GradientStops.Add( ... );
_myBrush = linearGradientBrush;
}
return _myBrush;
}
}
}
公共静态类笔刷
{
私有静态只读惰性\u myBrush=
新懒惰(()=>
{
var linearGradientBrush=新的linearGradientBrush{…};
linearGradientBrush.GradientStops.Add(…);
linearGradientBrush.GradientStops.Add(…);
返回线ArgRadientBrush;
}
);
公共静态线ArgRadientBrush MyBrush
{
获取{return\u myBrush.Value;}
}
}
懒惰的更简单,它清楚地表达了代码的意图。
它也是线程安全的
请注意,如果您在多个线程上实际使用此功能,则需要将其设置为[ThreadStatic]
;GDI+对象不能在线程之间共享。惰性
将正确处理并发场景(如果您传入了正确的),而您的示例没有任何线程安全检查。使用惰性
,因为它准确地表达了您正在做的事情-惰性加载
此外,它可以保持您的属性非常干净,并且是线程安全的。我通常会使用Lazy
:
- 它是线程安全的(在这种情况下可能不是问题,但在其他情况下可能是)
- 只凭名字就能清楚地知道发生了什么
- 它允许null为有效值
请注意,您不必为委托使用lambda表达式。例如,这里有一种方法可能稍微干净一些:
public static class Brushes
{
private static readonly Lazy<LinearGradientBrush> _myBrush =
new Lazy<LinearGradientBrush>(CreateMyBrush);
private static LinearGradientBrush CreateMyBrush()
{
var linearGradientBrush = new LinearGradientBrush { ...};
linearGradientBrush.GradientStops.Add( ... );
linearGradientBrush.GradientStops.Add( ... );
return linearGradientBrush;
}
public static LinearGradientBrush MyBrush
{
get { return _myBrush.Value; }
}
}
公共静态类笔刷
{
私有静态只读惰性\u myBrush=
新的Lazy(CreateMyBrush);
私有静态LinearGradientBrush CreateMyBrush()
{
var linearGradientBrush=新的linearGradientBrush{…};
linearGradientBrush.GradientStops.Add(…);
linearGradientBrush.GradientStops.Add(…);
返回线ArgRadientBrush;
}
公共静态线ArgRadientBrush MyBrush
{
获取{return\u myBrush.Value;}
}
}
当创建过程因循环等而变得复杂时,这尤其方便。请注意,从外观上看,您可以在创建代码中为GradientStops
使用集合初始值设定项
当然,另一个选择是不要懒洋洋地这么做。。。除非您的类中有几个这样的属性,并且您只希望逐个创建相关对象,否则在许多情况下都可以依赖惰性类初始化
正如DoubleDown的回答中所指出的,没有办法重置它以强制重新计算(除非您使惰性
字段不是只读的)-但我很少发现这一点很重要。如果您的性能大致相同,那么在缓存版本上使用Lazy
的唯一原因就是您不确定用户是否真的要加载属性
懒惰的要点是等待用户需要资源,然后及时在该实例中创建它。如果他们总是需要使用资源,那么使用Lazy
是没有意义的,除非您需要它的一些其他用途,例如它是线程安全的。通常不使用Lazy的唯一原因是将变量重置为null,以便下次访问时再次加载它。Lazy没有重置,您需要从头开始重新创建Lazy。Lazy有一些同步开销来提供线程安全性,而缓存属性是在任何其他代码之前通过CLR方式初始化的,您不需要支付同步成本
从可测试性的角度来看,Lazy是经过良好测试和验证的工件
然而,在我看来,与其他选项相比,使用Lazy
编写自己的实现的开销非常小。(当然,这是一种很好的方式。)有趣的是,我倾向于说它的代码更少,可读性更强,但您的示例表明情况并非如此。但是,我已经有了一个支持此行为和更常见的支持字段行为的支持字段的属性
类。Lazy允许线程安全在什么情况下使用Lazy是一个问题?@user256034:当您不使用.NET 4:)谢谢!您列表中的3点正是我要搜索的;)好的点数列表,如果你同意“双解”的答案,并且会考虑把他们的观点加在你的答案上,我会赞成:“TSEMER:这不是我个人认为有用的东西,但是我增加了一个小音符。看这个答案好点!IMHO,这与@JonSkeet的答案结合起来就是完整答案。-1,OP的替代方案是相同的,因为如果从未调用属性,那么列表就永远不会实例化。从这个意义上说,他们都是“懒惰的”。