什么时候懒加载?

时间:2011-10-13 13:39:43

标签: c# initialization lazy-loading

我懒得加载我的所有成员。我已经这样做了一段时间,只是懒得加载是一个好的面子值。

假设我们有

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()
       {

       }
    }

8 个答案:

答案 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对象,它仍然会被加载。

Link to Example

答案 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();

取消注释第一个循环,然后查看区别。非常有用的示例来说明延迟执行和延迟加载。