【问题标题】:How to prevent lazyloading of model property when assigning object?分配对象时如何防止模型属性的延迟加载?
【发布时间】:2019-08-02 08:39:37
【问题描述】:

我正在尝试在客户端的模型上实现一些延迟加载逻辑。

我试图将逻辑放在这些属性的 getter 中,但我现在意识到,当创建对象并将其分配给变量时,它会触发属性的所有 getter,从而触发延迟加载逻辑。

模型类:

    public class ProductStructure
    {
        public override Guid Id { get; set; }

        private List<AbstractStructureNode> subNodes;

        public override List<AbstractStructureNode> SubNodes
        {
            get
            {
                // Lazy loading logic including API calls to set subNodes
                return subNodes;
            }
            set
            {
                subNodes = value;
            }
        }
     }

API:

public async Task<ProductStructure> GetLightProductStructure(Guid Id)
        {
            if (Id == Guid.Empty)
                return null;

            string uri = ServiceUri + $"ProductStructures/Light/{Id}";
            using (var client = new HttpClient())
            {
                HttpResponseMessage response = client.GetAsync(uri).Result;

                if (!response.IsSuccessStatusCode)
                {
                    return null;
                }
                else
                {
                    string content = await response.Content.ReadAsStringAsync();
                    try
                    {
                        JsonSerializerSettings settings = new JsonSerializerSettings()
                        {
                            Formatting = Formatting.None,
                            TypeNameHandling = TypeNameHandling.Auto,
                            SerializationBinder = new CustomJsonSerializer("R3.ProductStructureSDK.DataModel", "R3.ProductStructureSDK")
                        };

                        return JsonConvert.DeserializeObject<ProductStructure>(content, settings);
                    }

                    catch (Exception e)
                    {
                        return null;
                    }
                }
            }
        }

触发延迟加载的赋值(单元测试的一部分)

ProductStructure LightProduct = await ProductStructureManager.Instance.GetLightProductStructure(RootId);

从服务器下载 ProductStructure 时,其子节点为空。但是将 API 返回的 ProductStructure 分配给变量“LightProduct”的简单事实将触发子节点的 getter。 API 使用异步方法,所以我不能使用 ref。

有没有一种通用的方法来延迟加载对象的属性?

【问题讨论】:

  • 我不明白您要达到的目标。对您而言,“延迟加载”模型的属性值有什么意义?
  • subNodes 属性可以包含数百个对象。当应用程序需要检索 ProductStructure 时,它​​不需要立即使用其 subnodes 属性。我简化了模型的代码,实际上它还包含一个描述字符串和其他我们首先需要的属性。

标签: c# lazy-loading variable-assignment getter


【解决方案1】:

没有。这是一种反模式。

您在 ProductStructure 类中隐藏了 IO / Api 调用。消费者不会知道这些电话的成本。

除非您有令人信服的理由使用外观模式(这就是您在此处实现的),否则我会将其分解为两个单独的调用。

-> Product
-> ProductDetails 

这将使您的代码更简洁,并且让维护您的代码的开发人员更容易理解。

【讨论】:

  • 好的,如果我搞定了,应用程序将不得不自己调用详细信息。我最初希望应用程序直接操作模型属性而不检查它是否已设置。我想这就是你所说的反模式部分。
  • 如果可能还有一个问题,如果模型属性已设置,我如何跟踪。特别是在服务器上没有数据且属性为空的情况下。我不想每次检测到未设置属性时都触发 API 调用。不过可能是另一个问题。
  • 为什么需要? REST 是无状态的。您要求提供数据 - 如果存在则显示。如果它为空,那么您已经知道服务器上没有数据。
  • 顺便说一下,您需要创建一个服务来包装 HttpClient 并隐藏所有 JSON 处理。要么,要么创建你自己的“JsonClient”,它做同样的事情。你可以避免这样重复很多代码:)
【解决方案2】:

只要您使用

反序列化数据

return JsonConvert.DeserializeObject&lt;ProductStructure&gt;(content, settings);

然后创建数百个子节点并将其加载到内存中。您不能为您的方案延迟加载 ProductStructure 中的任何内容。 你应该做的是创建一个“LightProductStructure”类

public class LightProductStructure
{
    public override Guid Id { get; set; }
}

如果您需要一个没有子节点的对象,请使用 LightProductStructure 对象反序列化服务器的响应。如果您需要 与 子节点,则使用 ProductStructureObject 反序列化服务器的响应。

为了使您的代码更简洁,您还应该像这样重构 ProductStructure 对象

public class ProductStructure : LightProductStructure
{
    private List<AbstractStructureNode> subNodes;

    public override List<AbstractStructureNode> SubNodes
    {
        get
        {
            // Lazy loading logic including API calls to set subNodes
            return subNodes;
        }
        set
        {
            subNodes = value;
        }
    }
 }

编辑: 另一种没有继承的方法是 - 在某些情况下 - 将子节点作为字符串存储在 ProductStructure 对象中。这样您就无需加载数百个对象,您只需在内存中保存一个字符串。 然后,当您需要这些对象时,调用 ProductStructure 对象上的一个方法,该方法将反序列化该字符串,并将结果分配给您的 Subnodes 属性。我认为这是您在那种情况下谈论的延迟加载方法最接近的方法。

【讨论】:

  • 我明白你的意思,但因为我不希望服务器在我每次请求 ProductStructure 时都包含子节点,所以我在 API 中有几个路由。其中之一 (ProductStructures/Light/{Id}) 已经返回没有子节点的轻型产品。反序列化部分工作正常,GetLightProductStructure 返回的对象不包含任何对我来说很好的子节点。
  • 在这种情况下,调用“light”API 的方法应该返回一个“light”对象。每当您需要访问“完整”对象时,再次调用“完整”API 以检索您的“完整”对象。不要让这种逻辑存在于您的模型中。在应用程序的业务/逻辑层中处理这些。模型应该是一个逻辑非常简单的“哑”数据容器
  • 这听起来更好,我会考虑一下
猜你喜欢
  • 2014-04-12
  • 2014-03-15
  • 1970-01-01
  • 2022-08-13
  • 1970-01-01
  • 1970-01-01
  • 2017-02-20
  • 1970-01-01
相关资源
最近更新 更多