首页 > 代码库 > C#中的延迟加载

C#中的延迟加载

什么是延迟加载?  

  延迟加载顾名思义就是:推迟加载的时机,当真正使用的时候才加载

  通常在创建一个大对象时,有些属性我们可以在使用到的时候才去创建(设置属性的值),这个可以有效的提升系统性能。  

示例:

/定义了一个Hero类型
public class Hero
{
    public string Name{get;set;}
    
    public string FullName{get;set;}
    
    public Skill objSkill;
    
    public Hero(string name)
    {
        Name=name;
        FullName="Super "+name;
        objSkill=new Skill(name);
    }
}

//定义一个Skill类型
public class Skill
{
    public string Name{get;set;}
    
    public int Power{get;set;}
    
    public Skill(string name)
    {
        Name=name;
        Power=name.Length;
    }
}


public class Program
{
    public static void Main(string[] args)
    {
        Hero hero=new Hero("qi da sheng");
        //此时我只想获取Hero的FullName,但是同时调用Skill的构造方法,加载了Skill的属性,
        //初始化Skill需要在内存中开辟一定的空间,造成没必要的空间浪费
        Console.WriteLine(hero.FullName);
        
        //思考:如果实现在调用Skill.Name的时候才去真正创建Skill对象呢?
    }
}

改进一

改进一:
//定义了一个Hero类型
public class Hero
{
    public string Name{get;set;}
    
    public string FullName{get;set;}
    
    //public Skill objSkill;
    private Skill _skill;
    
    public Skill objSkill
    {
        get {return _skill??(new _skill(Name));}
    }
    
    public Hero(string name)
    {
        Name=name;
        FullName="Super "+name;
        //objSkill=new Skill(name);
    }
}

//定义一个Skill类型
public class Skill
{
    public string Name{get;set;}
    
    public int Power{get;set;}
    
    public Skill(string name)
    {
        Name=name;
        Power=name.Length;
    }
}


public class Program
{
    public static void Main(string[] args)
    {
        Hero hero=new Hero("qi da sheng");
        //此时获取Hero的FullName时并不会去创建Skill的实例
        Console.WriteLine(hero.FullName);
        //真正用到Skill.Name时才会创建Skill的实例,从而实现了延迟加载效果?
        Console.WriteLine(hero.ObjSkill.Power);
        
        //思考2:有没有其他更好的方法?
    }
}

改进二

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Demo_Lazy
{
    //定义了一个Hero类型
    public class Hero
    {
        public string Name { get; set; }

        public string FullName { get; set; }

        private readonly Lazy<Skill> skill;

        public Skill objSkill
        {
            get { return skill.Value; }
        }

        public Hero(string name)
        {
            Name = name;
            FullName = "Super " + name;
            skill = new Lazy<Skill>(() => new Skill(Name));
        }
    }

    //定义一个Skill类型
    public class Skill
    {
        public string Name { get; set; }

        public int Power { get; set; }

        public Skill(string name)
        {
            Name = name;
            Power = name.Length;
        }
    }


    public class Program
    {
        public static void Main(string[] args)
        {
            Hero hero = new Hero("qi da sheng");
            //此时获取Hero的FullName时并不会去创建Skill的实例
            Console.WriteLine(hero.FullName);
            //真正用到Skill.Name时才会创建Skill的实例,从而实现了延迟加载效果
            Console.WriteLine(hero.objSkill.Power);

            Console.Read();
        }
    }


}

 

Lazy<T>的优势

那么既然我们已经可以用属性缓存的方法实现, 为什么还要引入Lazy<T> ?

至少Lazy<T> 有以下几点优势:

  1. 它具有 LazyThreadSafetyMode, 但是我们一般不使用它, 除非是很关键的情况下(在此略去181个字) 
  2. 它使属性的定义行更加简单 
  3. 从语义上来讲, 它更加明确, 更加具有可读性 
  4. 它允许null为有效值

C#中的延迟加载