什么时候懒加载?

问题描述 投票:9回答:8

我懒得加载我的所有成员。我已经这样做了一段时间,只是采取懒惰的负载,在面值是一件好事。

让我们说我们有

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甚至是否重要)?


After what I have learned from your answers, I would like to know if there is any difference between the above and this...
public class SomeClass
    {
       public int anInt;
       public SomeReferenceType member1 = new SomeReferenceType();

       public SomeClass()
       {

       }
    }
c# initialization lazy-loading
8个回答
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为你处理问题并使事情变得更容易。

其次,延迟加载是一个好主意,当你有许多成员加载成本高,并且你确定你将使用所有这些值。该成本将导致类型实例化的速度不一定很慢。

为了延迟加载而延迟加载会给代码增加不必要的复杂性,如果做得不正确(例如处理线程时)可能会导致问题。


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;
        }
    }
}

至于为什么,如果您创建的对象往往是昂贵的(内存或时间)并且无法保证您将需要它,通常延迟加载是一个很好的方案。如果你有理由确定它将永远使用,那么你应该直接构造它。


6
投票

从我看到的代码,你没有做懒惰的负载。您正在构造函数中初始化成员,这些成员总是会发生并在实例的生命周期中很快发生。

因此,我想知道,什么是非懒加载?

延迟加载通常是在您访问它时仅初始化某些内容时。

这里有一个例子,使用.NET 4.0 Lazy类,它可以帮助你做到这一点,延迟加载:

public class Foo
{
    private Lazy<int> _value = new Lazy<int>(() => 3);

    public int Value { get { return _value.Value; } }
}

关于线程安全 - 你可以传递第二个参数LazyThreadSafetyMode,它知道指定线程安全的两种方法:一种初始化方法的执行可能会多次发生,但是所有线程都获得首先创建的值,或者其中一个执行也受到保护,不会被多次运行。


0
投票

这不是延迟加载。

延迟加载意味着您​​只需在实际访问时加载该值(在初始化程序中不会发生)

延迟加载是这样的:

private SomeClass _someRef = null;
public SomeClass SomeRef
{
  get
  {
    if(_someRef == null)
    {
       //initialisation just in case of access
       _someRef = new  SomeClass();
    }
    return _someRef;
  }
}

0
投票

int的真正延迟加载属性可能如下所示:

private int? _heavyLoadedInt;

public int HeavyLoading
{
    get
    {
        if (_heavyLoadedInt == null)
            _heavyLoadedInt = DoHeavyLoading();
        return _heavyLoadedInt.Value;
    }
}

现在,如果你看一下,你会发现这里有一些开销:你必须将值存储在可空(额外的内存)中;在每次访问时检查null,并在每次访问时从nullable中检索值。

如果你的整数真的需要一些非常繁重的计算,那么这个结构是有意义的。但new int()不是一个繁重的计算,它只是返回0。开销很小,但是如果你将这个开销添加到更简单的操作(即读取整数),那就没有意义了。


0
投票

当对象创建的成本非常高并且对象的使用很少时,延迟加载是必不可少的。所以,这是值得实现延迟加载的场景。延迟加载的基本思想是在需要时加载对象/数据


0
投票

延迟加载是一个概念,我们将对象的加载延迟到我们需要它的位置。简单地说,按需加载对象而不是不必要地加载对象。

例如,考虑下面的示例,其中我们有一个简单的Customer类,并且此Customer类中包含许多Order对象。仔细查看Customer类的构造函数。创建Customer对象时,它还会在此时加载Order对象。因此,即使我们需要或不需要Order对象,它仍然会被加载。

Link to Example


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

取消注释第一个循环,看看差异。非常使用示例来表示deffred执行和延迟加载。

© www.soinside.com 2019 - 2024. All rights reserved.