C# 当对象位于自己的DLL中时,如何实现自己的延迟加载

C# 当对象位于自己的DLL中时,如何实现自己的延迟加载,c#,lazy-loading,C#,Lazy Loading,如果这已经得到了回答,我道歉,但我找不到任何答案 在最近的一次采访中,我被问到如何实现延迟加载。情况如下: 解决方案: 网站项目 default.aspx 对象集合项目 命令 行项目 服务层 订单服务 存储库层 订单存储库 Order对象将具有IList。订单存储库将有一个返回所有订单的方法(为了更快,它不会返回每个订单的所有行项目,因此它将为空) 问题是“我如何对Order对象进行延迟加载。例如,有一个Order对象,网站调用myOrder.LineItems 我的第一个想

如果这已经得到了回答,我道歉,但我找不到任何答案

在最近的一次采访中,我被问到如何实现延迟加载。情况如下:

解决方案:

  • 网站项目
    • default.aspx
  • 对象集合项目
    • 命令
    • 行项目
  • 服务层
    • 订单服务
  • 存储库层
    • 订单存储库
Order对象将具有IList。订单存储库将有一个返回所有订单的方法(为了更快,它不会返回每个订单的所有行项目,因此它将为空)

问题是“我如何对Order对象进行延迟加载。例如,有一个Order对象,网站调用myOrder.LineItems

我的第一个想法是,Order对象会调用Order服务来获取行项目,但这不是一个好的设计,因为对象需要了解服务,服务需要了解对象。当然,网站可以调用Order服务并传递Order/Order ID来获取行项目,但我们怎么能呢使该位不可见?因此Order对象保存其所有数据,但某些数据仅在需要时加载

谢谢,希望一切都有意义


Jon

您可以使用
lazy
类存储对列表的惰性引用

该类的一个构造函数接收一个
Func
,该函数用于在请求时实例化/检索实际值

一种可能的解决方案是将该函数注入到Order对象中,并用以下内容初始化:

var getlines = () => orderService.GetLineItems(orderId);

在那之后,它只是用一个属性来包装懒惰的人。

作为面试官,我会在答案中寻找三件事

  • 了解ORM框架如何处理延迟加载
  • 承认如果不考虑现有框架,您将无法在生产中实现这一点
  • “自产”解决方案的实际设计
我会这样回答这个问题

惰性加载由诸如NHibernate或Entity Framework之类的ORM框架实现的公共功能

如果一个ORM框架是不可能的,我将使用一个拦截框架(如Castle拦截或Unity拦截)实现延迟加载(第2点)

为了从头开始实现延迟加载,我将使用一个装饰器模式(奖励点),对Order类进行子类化,并在那里定义延迟加载行为。下面是显示相关属性的设计:

class Order {
 public int ID {get;set;}
 public virtual IList<OrderLine> Lines{get;set;} 
}

interface IOrderRepository {
  Order GetOrder(id);
  IList<OrderLine> GetOrderLines(Order order);
}

class OrderService {

 IOrderRepository _repository;

 public OrderService(IOrderRepository repository) {
  _repository = repository;
 }

 public Order GetOrder(int id) {
   return new OrderDecorator(_repository.GetOrder(id));
 }
}

public class OrderDecorator : Order {
  public OrderDecorator (IOrderRepository repository) {
    _OrderLines = new Lazy<IList<OrderLine>>(()=>repository.GetOrderLines(this));
  }

  Lazy<IList<OrderLine>> _OrderLines;

  public override IList<OrderLine> Lines {
    get {
      if (base.OrderLines == null) 
        base.OrderLines = _OrderLines.Value;
      return base.OrderLines; 
    } 
    set {base.OrderLines=value;}
  } 
}
类顺序{
公共int ID{get;set;}
公共虚拟IList行{get;set;}
}
存储库接口{
订单获取订单(id);
IList GetOrderLines(订单);
}
类订单服务{
IOrderRepository \u repository;
public OrderService(IOrderRepository存储库){
_存储库=存储库;
}
公共秩序(内部id){
返回新的OrderDecorator(_repository.GetOrder(id));
}
}
公共类OrderDecorator:Order{
public OrderDecorator(IOrderRepository存储库){
_OrderLines=newlazy(()=>repository.GetOrderLines(this));
}
懒惰的订单线;
公共线{
得到{
if(base.OrderLines==null)
base.OrderLines=\u OrderLines.Value;
返回base.OrderLines;
} 
set{base.OrderLines=value;}
} 
}
这是一个没有惰性幻想的版本。在编辑以确保代码严格符合装饰器模式后,惰性版本实际上没有添加任何内容,因此我只使用下面的版本

public class OrderDecorator : Order {
  public OrderDecorator (IOrderRepository repository) {
    _Repo = repository;
  }
  IOrderRepository _Repo;

  public override IList<OrderLine> Lines {
   get {
     if (base.OrderLines == null)
       base.OrderLines = repository.GetOrderLines(this);

     return base.OrderLines; 
   } 
   set {base.OrderLines=value;}
 }
}
公共类OrderDecorator:Order{
public OrderDecorator(IOrderRepository存储库){
_Repo=存储库;
}
iorderrepo;
公共线{
得到{
if(base.OrderLines==null)
base.OrderLines=repository.GetOrderLines(此);
返回base.OrderLines;
} 
set{base.OrderLines=value;}
}
}
更新这是项目布局。有一条关于耦合订单和存储库的评论。事实并非如此,因为存储库耦合到了装饰器,而不是订单

  • 对象集合项目
    • 命令
    • 行项目
  • 服务层
    • 订单服务
  • 存储库层
    • 订单存储库
    • OrderDecorator

第1点和第2点非常有效和有用。代码示例(据我所知)仍然将Order对象和IOrderRepo/Service紧密地联系在一起。感谢您的帮助和输入。@Jon实际上没有。如果您仔细看,服务引用在OrderDecorator中,而不是Order中。这与ORM框架的功能非常接近。更新了文章,提供了有关实体所在位置的更多详细信息。啊,我想我明白了。这非常有趣ting方法。我了解您现在的情况。项目概述真的很有帮助。谢谢:)@IgorZevaka我喜欢这个示例,但是我无法编译它。OrderService中的GetOrder方法似乎正在尝试新建OrderDecorator,但它正在传递由_repository.GetOrder调用返回的Order类。OrderDecorator或者构造函数正在查找IORDERepository。