如何获得 List<T> 的唯一 ID

How can I get a unique id for a List<T>

我有一个 List<T>,其中 T 是一个 class,它有一个 int 字段用于 id。获得未在 List<T> 中的任何对象中使用的唯一 id 值的最佳方法是什么?

这个程序一般是怎么编码的?是否有数据类型可以帮助解决这个问题,或者我是否需要存储最大的 id 值?

编辑

当我获得一个对象的 ID 为 1 时怎么样?然后我从列表中删除该对象。当我创建一个新对象时,我希望唯一标识为 2。在这种情况下,有没有比存储最后一个唯一标识更好的方法?

谢谢。

对于这种方法,我会编写一个继承的 class 的 List 来保存逻辑,因此您不需要在访问列表的任何地方都实现它。 如果您有一个具有 Id 值的最小接口,您甚至可以保留它的通用性。

interface IWithId {
    int Id { get; set; }
}

class CustomList<T> : List<T> where T : class, IWithId {
    private lastUsedId = 1;

    public void AddObjectWithAutomaticId(T newObject) {
        newObject.Id = lastUsedId++;
        base.Add(newObject);
    }

    public T GetElementById(int id) {
         return base.SingleOrDefault(p => p.Id == id);
    }
}

Remove 方法仍然可以像以前一样工作。 class 存储最后使用的 Id,独立于您删除的内容。 Add 方法也仍然可用,当您想要添加具有给定 Id 的对象而不是自动填充它时。

我同意 GUID 适合您作为 ID 属性 的评论。但是,如果您需要使用 int 那么我建议使用新的 class.

继承List<T>的问题是你必须覆盖多个方法来确保Add()AddRange()Insert()之类的东西不能添加复制 ID 并更新存储的最大 ID。很容易错过一个。

我会使用不继承任何东西但在内部使用字典的 class。这不会有与 List<T> 完全相同的方法,但这不一定是坏事 - 它可以避免犯错误,你可以有一个 ToList() 方法,当他们想要查询它时就好像这是 List<T>.

使用先前答案的一部分来确保 T 具有 Id 属性 给出:

interface IHasId {
    int Id { get; set; }
}

class AutoIdList<T> where T : class, IHasId {
    private readonly IDictionary<int, T> _dictionary = new Dictionary<int, T>();
    //Using this list ensures you don't duplicate ids even
    //for an item added with an explicit id then removed
    private IList<int> _historicalIds = new List<int>();
    private int highestAutoGeneratedId = 0;

    public List<T> ToList() {
        return _dictionary.Values.ToList();
    }

    public void Add(T item, bool generateId) {
        if (generateId) {
            highestAutoGeneratedId = NextId();
            T.Id = highestAutoGeneratedId;
        }
        Add(T);
    }

    public void Replace(T item) {
        _dictionary[item.Id] = item;
    }

    public void Remove(T item) {
        _dictionary.Remove(item.Id);
    }

    private void Add(T item) {
        if (_historicalIds.Contains(T.Id)) {
            //throw an appropriate exception
        } else {
            _historicalIds.Add(T.Id);
            _dictionary.Add(T.Id, T);
        }
    }

    private int NextId() {
        var id = highestAutoGeneratedId + 1;
        while (_historicalIds.Contains(id)) {
            id++;
        }
        return id;
    }

    //More methods to simulate AddRange, Insert, etc if required. Leave if not.
    //Should all have simple logic but require checking of Id if adding anything
    //Also need logic to maintain the list of used ids
}