如何获得 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
}
我有一个 List<T>
,其中 T
是一个 class,它有一个 int
字段用于 id
。获得未在 List<T>
中的任何对象中使用的唯一 id
值的最佳方法是什么?
这个程序一般是怎么编码的?是否有数据类型可以帮助解决这个问题,或者我是否需要存储最大的 id 值?
编辑
当我获得一个对象的 ID 为 1 时怎么样?然后我从列表中删除该对象。当我创建一个新对象时,我希望唯一标识为 2。在这种情况下,有没有比存储最后一个唯一标识更好的方法?
谢谢。
对于这种方法,我会编写一个继承的 class 的 List
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
}