首页 > 解决方案 > 检查列表中已删除的插槽

问题描述

我想Items用 ID 生成一些。Item只是一个具有 ID 整数属性的类。创建它们后,它们应该被添加到列表中。所以我有一个管理所有项目的类

internal static class ItemPool
{
    public static readonly List<Item> items = new List<Item>(); // Store all the items here

    public static Item CreateItem()
    {
        int itemId = items.Count; // Just take the next free slot index
        Item itemToCreate = new Item(itemId);
        items.Add(itemToCreate);
        return itemToCreate;
    }

    public static void DestroyItem(int itemId)
    {
        activeItems.RemoveAt(itemId);
    }
}

现在我可以创建一些项目

Item firstItem = ItemPool.CreateItem(); // generates item with ID 0

Item secondItem = ItemPool.CreateItem(); // generates item with ID 1

ItemPool.DestroyItem(firstItem.id); // Recudes the list count to 1

Item thirdItem = ItemPool.CreateItem(); // generates item with ID 1 - ERROR

第三项不允许有 ID 1,因为第 2 项已经有了它。

更改代码时会出现两个问题:

如何管理此列表中项目的 ID,以使它们都没有相同的 ID?

public static Item CreateItem()
{
    int itemId = temporaryUniqueId; // create a temporary unique ID
    // ... other code
}

有什么比去更优化的方式

public static void DestroyItem(int itemId)
{
    activeItems = activeItems.Where(item => item.id != itemId).ToList();
}

我知道我能做到

public static void DestroyItem(Item item)
{
    activeItems.Remove(item);
}

但我认为通过 ID 删除更安全。我问这个是因为对于这种情况,性能就是一切

ID 不必是整数值

标签: c#

解决方案


由于不需要将 ID 作为整数,因此一种方法是使用 aGUID作为唯一标识符以避免处理潜在的冲突。

public class Item 
{
    public Guid Id { get; }

    public Item()
    {
        Id = Guid.NewGuid();
    }
}

然后,您的ItemPool类可以更改为使用 a ConcurrentDictionary(以避免任何竞争条件):

internal sealed class ItemPool
{
    private readonly ConcurrentDictionary<Guid, Item> items = new ConcurrentDictionary<Guid, Item>(); // Store all the items here

    public Item CreateItem()
    {
        Item itemToCreate = new Item();
        items.TryAdd(itemToCreate.Id, itemToCreate);
        return itemToCreate;
    }

    public void DestroyItem(Guid itemId)
    {
        activeItems.TryRemove(itemId, out Item _);
    }
}

我冒昧地删除了该类的静态参数以使其更易于测试。为了更好地封装,我还将该items字段设为私有。您不希望任何其他类绕过ItemPool并开始自己操作集合:)


推荐阅读