如何在C#中延迟加载?

How to lazy load in C#?
2021-02-23
  •  译文(汉语)
  •  原文(英语)

我正在开发游戏模拟器.我有一个名为"Map"的对象,其中包含地图的ID和有关它的其他各种信息.游戏包含许多地图对象(约10,000个).数据位于SQL表内部,因此我正在使用它来加载它.

我有一个名为int的类CachedMaps,它继承自KeyedCollectionint和map.标识符是地图的ID.不幸的是,加载所有地图大约需要5秒钟.

无论如何,并不是所有的地图都会被访问.我的朋友建议我使用"延迟加载",我不确定该怎么做-例如,仅当用户输入地图时才加载地图的数据或对象.这怎么可能?谢谢.

public class CachedMaps : KeyedCollection<int, Map>
{
    public CachedMaps()
        : base()
    {
        // The loading code.
        // this.Add(new Map(....));
    }
}
速聊1:
为什么选择KeyedCollection缓存的基类?
解决过程1

您应该使用Lazy泛型类,其目的正是该类.

使用MSDN中的示例:("大对象"就是您的地图):

lazyLargeObject = new Lazy<LargeObject>(() => 
{
    LargeObject large = new LargeObject(Thread.CurrentThread.ManagedThreadId);
    // Perform additional initialization here. 
    return large;
});
速聊1:
很抱歉,但是我将在哪里使用该代码?
速聊2:
您可以实例化一个新的Lazy而不是nw Map,并在需要时使用th lazy的Value属性来访问您的地图.
速聊3:
var lazyCachedMaps = new Lazy<CachedMaps>();然后,当您要访问这些地图时,请使用var cachedMaps = lazyCachedMaps.Value;.查看构造函数文档,以了解构建此Lazy类型所需的选项(如果有).
速聊4:
您介意向我展示其用法的完整示例吗?谢谢.
解决过程2

我想,如果您可以调用数据库来加载地图,那么对您来说最好的方法就是物理上的延迟加载(或者就是我所说的).

这里的概念是,在第一次加载时,您仅会获得用户选择地图所需的信息...您的操作方式取决于您...带有地图名称和ID的下拉列表...带有相关ID的小屏幕截图列表(我在这里是游戏).

然后,只有用户选择了地图,它才可以从数据库中获取完整的地图信息.同样,由于您提到对象很大,因此II将仅缓存"选择地图"部分的地图标识符列表,而不缓存地图本身...对于这种简单情况:如果我正在测试您的东西,该怎么办,然后运行最终方案,即加载所有地图.如果所有这些都被缓存,则将耗尽内存.

无论如何我就是那样做的...

解决过程3

只需创建一个包含的类Dictionary,而不是一个覆盖a的类KeyedCollection:

public class CachedMaps
{
    private readonly Dictionary<int, Map> _maps = new Dictionary<int, Map>();

    public Map GetMap(int mapId)
    {
        if (!this._maps.ContainsKey(mapId))
        {
            this._maps[mapId] = this.Add(new Map(....));
        }
        return this._maps[mapId];
    }
}

现在,地图将按需加载,然后进行缓存.

I'm developing an emulator for a game. I have an object named "Map", which contains the map's id, and other various information about it. The game contains a lot of map objects (about 10,000). The data is located inside a SQL table, so I'm using that to load it.

I have a class named CachedMaps which inherits from a KeyedCollection of int and map. The identifier is the map's id. Unfortunately, it takes about 5 seconds to load all the maps.

Not all the maps will be visited, anyway. My friend suggested that I would use "lazy loading", I'm not sure how to do it - like, load the map's data or object only when a user enters it. How is it possible? Thank you.

public class CachedMaps : KeyedCollection<int, Map>
{
    public CachedMaps()
        : base()
    {
        // The loading code.
        // this.Add(new Map(....));
    }
}
Talk1:
Why do you choose KeyedCollection for base class for your cache?
Talk2:
Solutions1

You should use the Lazy generic class whose purpose is exactly that.

Use example from MSDN : (the "large object" would be your map):

lazyLargeObject = new Lazy<LargeObject>(() => 
{
    LargeObject large = new LargeObject(Thread.CurrentThread.ManagedThreadId);
    // Perform additional initialization here. 
    return large;
});
Talk1:
I'm sorry, but where exactly would I use that code?
Talk2:
you instanciate a new Lazy instead of your nw Map, and use the Value property of th lazy to access your map, when your need it.
Talk3:
var lazyCachedMaps = new Lazy<CachedMaps>(); then when you want to access these maps use var cachedMaps = lazyCachedMaps.Value;. Check out the constructor docs to see what kind of options you need to construct this Lazy type with, if any.
Talk4:
Do you mind showing me a full example of how it's used? Thanks.
Solutions2

Im my mind, the best way for you IF you're ok with making a call to the DB to load a map, would be a physical lazy load (or that's what I call it).

The concept here is that on first load, you only get the information you need for the user to CHOOSE a map... how you do that is up to you... a drop-down with the map names and IDs... a list of small screenshots (I'm thinking game here) with associated ID.

Then, ONLY once the user selects a map does it go and get the full map information from the DB. As well, since you mention that the object is large, I I would only cache the list of map identifiers for the "select a map" part, and NOT the maps themselves... for this simple scenario: What if I am testing your stuff, and run the ultimate scenario which is to load ALL maps. If all of these get cached, you'll run out of memory.

That's how i would do it anyway...

Solutions3

Just create a class containing a Dictionary, not one overriding a KeyedCollection:

public class CachedMaps
{
    private readonly Dictionary<int, Map> _maps = new Dictionary<int, Map>();

    public Map GetMap(int mapId)
    {
        if (!this._maps.ContainsKey(mapId))
        {
            this._maps[mapId] = this.Add(new Map(....));
        }
        return this._maps[mapId];
    }
}

Now maps are loaded on demand and then cached.

转载于:https://stackoverflow.com/questions/23712226/how-to-lazy-load-in-c

本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文

留言回复
我们只提供高质量资源,素材,源码,坚持 下了就能用 原则,让客户花了钱觉得值
上班时间 : 周一至周五9:00-17:30 期待您的加入