我懒得加载我的所有成员。我已经这样做了一段时间,只是懒得加载是一个好的面子值。
假设我们有
public class SomeClass
{
public int anInt;
public SomeReferenceType member1;
public SomeClass()
{
//initialize members in constructor when needed (lazy load)
anInt = new int();
member1 = new SomeReferenceType();
}
}
以这种方式做事有什么不利之处吗?这是一个适当的延迟加载模式吗?延迟加载值类型是否有意义(现代RAM甚至是否重要)?
<小时/> 根据我从你的答案中学到的东西,我想知道上述和这之间是否有任何区别......
public class SomeClass
{
public int anInt;
public SomeReferenceType member1 = new SomeReferenceType();
public SomeClass()
{
}
}
答案 0 :(得分:17)
首先,初始化构造函数内的成员不是延迟加载。
延迟加载是在第一次请求时初始化成员。 .NET中的一个简单示例(带有一些双重检查锁定,因此我们没有线程问题):
public class SomeClass
{
private object _lockObj = new object();
private SomeReferenceType _someProperty;
public SomeReferenceType SomeProperty
{
get
{
if(_someProperty== null)
{
lock(_lockObj)
{
if(_someProperty== null)
{
_someProperty= new SomeReferenceType();
}
}
}
return _someProperty;
}
set { _someProperty = value; }
}
}
幸运的是,如果你使用的是.NET 4,你现在可以使用Lazy<T>
Class为你处理问题并使事情变得更容易。
其次,延迟加载是一个好主意,当你有许多成员加载成本高,并且你确定你将使用所有这些值。这个成本会导致类型实例化的速度不一定很慢。
延迟加载只是为了延迟加载会给你的代码增加不必要的复杂性,如果做得不正确(例如,在处理线程时)可能会导致问题。
答案 1 :(得分:8)
这不是一个懒惰的负载。这是在建设初期。通常我们在延迟加载中的意思是在第一次引用时构造项目。
private string _someField;
public string SomeField
{
get
{
// we'd also want to do synchronization if multi-threading.
if (_someField == null)
{
_someField = new String('-', 1000000);
}
return _someField;
}
}
它曾经是懒惰加载的典型方法之一是检查,锁定,检查,如果它已经创建你就不会锁定,但是因为它可能有两个项目通过检查并等待锁定,你再次检查锁:
public class SomeClass
{
private string _someField;
private readonly object _lazyLock = new object();
public string SomeField
{
get
{
// we'd also want to do synchronization if multi-threading.
if (_someField == null)
{
lock (_lazyLock)
{
if (_someField == null)
{
_someField = new String('-', 1000000);
}
}
}
return _someField;
}
}
}
有多种方法可以做到这一点,实际上在.NET 4.0中,有一种Lazy<T>
类型可以帮助您轻松地进行线程安全的延迟加载。
public class SomeClass
{
private readonly Lazy<string> _someField = new Lazy<string>(() => new string('-', 10000000), true);
private readonly object _lazyLock = new object();
public string SomeField
{
get
{
return _someField.Value;
}
}
}
至于为什么,如果您正在创建的对象往往是昂贵的(内存或时间)并且无法保证您将需要它,通常延迟加载是一个很好的方案。如果您有理由确定它将永远使用,那么您应该直接构建它。
答案 2 :(得分:6)
从我看到的代码中,你没有做懒加载。您正在构造函数中初始化成员,这些成员总是会发生并在实例的生命周期中很快发生。
因此,我想知道,什么是非延迟加载?
延迟加载通常是在您访问它时仅初始化某些内容。
这是一个使用.NET 4.0 Lazy类的例子,它可以帮助你做到这一点,延迟加载:
public class Foo
{
private Lazy<int> _value = new Lazy<int>(() => 3);
public int Value { get { return _value.Value; } }
}
关于线程安全 - 您可以传递第二个参数LazyThreadSafetyMode
,它知道指定线程安全的两种方法:一种初始化方法的执行可能会多次发生,但是所有线程都获得的值首先创建,或者执行也被保护以防止多次运行。
答案 3 :(得分:0)
这不是延迟加载。
延迟加载意味着您只需在实际访问时加载该值(在初始化程序中不会发生)
延迟加载是这样的:
private SomeClass _someRef = null;
public SomeClass SomeRef
{
get
{
if(_someRef == null)
{
//initialisation just in case of access
_someRef = new SomeClass();
}
return _someRef;
}
}
答案 4 :(得分:0)
int的真正延迟加载属性可能如下所示:
private int? _heavyLoadedInt;
public int HeavyLoading
{
get
{
if (_heavyLoadedInt == null)
_heavyLoadedInt = DoHeavyLoading();
return _heavyLoadedInt.Value;
}
}
现在,如果你看一下,你会发现这里有一些开销:你必须将值存储在可空(额外的内存)中;在每次访问时检查null
,并在每次访问时从可空值中检索值。
如果你的整数真的需要一些非常繁重的计算,那么这个结构是有道理的。但是new int()
不是一个繁重的计算,它只返回0
。开销很小,但是如果你把这个开销添加到更简单的操作(即读取一个整数),那就毫无意义了。
答案 5 :(得分:0)
当对象创建的成本非常高并且对象的使用很少时,延迟加载是必不可少的。所以,这是值得实现延迟加载的场景。 延迟加载的基本思想是在需要时加载对象/数据
答案 6 :(得分:0)
惰性加载是一个概念,其中我们将对象的加载延迟到需要它的位置。简而言之,按需加载对象而不是不必要地加载对象。
例如,请考虑以下示例,其中我们有一个简单的Customer类,并且该Customer类中包含许多Order对象。仔细研究Customer类的构造函数。创建Customer对象时,它还将同时加载Order对象。因此,即使我们需要或不需要Order对象,它仍然会被加载。
答案 7 :(得分:0)
List<int> number = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var result = number.Where(x => x % 2 == 0);
number.Add(20);
//foreach (int item in result)
//{
// Console.WriteLine("loop1:" + item);
//}
foreach (int item in result)
{
if (item == 4)
break;
Console.WriteLine("loop2:" + item);
}
number.Add(40);
foreach (int item in result)
{
Console.WriteLine("loop3:"+item);
}
Console.ReadLine();
取消注释第一个循环,然后查看区别。非常有用的示例来说明延迟执行和延迟加载。