有没有办法为每个新的类对象创建自动增量ID?因此,如果我创建了5个新的机器人,它们的ID分别为1、2、3、4、5。如果我然后销毁机器人2并稍后创建一个新的机器人,它将具有ID 2。如果我添加第6个,它将具有ID 6,依此类推...
谢谢。
Interlocked.Increment(ref nextId)
。class Robot {
static int nextId;
public int RobotId {get; private set;}
Robot() {
RobotId = Interlocked.Increment(ref nextId);
}
}
注意:仅在非并发环境中,使用nextId++
是有效的;Interlocked.Increment
可以处理您从多个线程分配机器人的情况。
编辑:这不涉及重新使用机器人ID。如果需要重用,解决方案要复杂得多:您需要一个可重用ID列表,并在访问该列表的代码周围使用ReaderWriterLockSlim
。
class Robot : IDisposable {
static private int nextId;
static private ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
static private IList<int> reuseIds = new List<int>();
public int RobotId {get; private set;}
Robot() {
rwLock.EnterReadLock();
try {
if (reuseIds.Count == 0) {
RobotId = Interlocked.Increment(ref nextId);
return;
}
} finally {
rwLock.ExitReadLock();
}
rwLock.EnterWriteLock();
try {
// Check the count again, because we've released and re-obtained the lock
if (reuseIds.Count != 0) {
RobotId = reuseIds[0];
reuseIds.RemoveAt(0);
return;
}
RobotId = Interlocked.Increment(ref nextId);
} finally {
rwLock.ExitWriteLock();
}
}
void Dispose() {
rwLock.EnterWriteLock();
reuseIds.Add(RobotId);
rwLock.ExitWriteLock();
}
}
注意2:如果您希望在重用ID时优先使用较小的ID(而不是像我编码的那样先重用早期发布的ID再重用后期发布的ID),则可以将IList<int>
替换为SortedSet<int>
,并在从集合中获取要重用的ID的部分进行一些调整。
这样做可以解决问题,并以一种良好的线程安全方式运行。当然,由您自己处理机器人的处置等事宜。显然,对于大量机器人来说效率不高,但有很多方法可以解决这个问题。
public class Robot : IDisposable
{
private static List<bool> UsedCounter = new List<bool>();
private static object Lock = new object();
public int ID { get; private set; }
public Robot()
{
lock (Lock)
{
int nextIndex = GetAvailableIndex();
if (nextIndex == -1)
{
nextIndex = UsedCounter.Count;
UsedCounter.Add(true);
}
ID = nextIndex;
}
}
public void Dispose()
{
lock (Lock)
{
UsedCounter[ID] = false;
}
}
private int GetAvailableIndex()
{
for (int i = 0; i < UsedCounter.Count; i++)
{
if (UsedCounter[i] == false)
{
return i;
}
}
// Nothing available.
return -1;
}
还有一些测试代码,以加深认识。
[Test]
public void CanUseRobots()
{
Robot robot1 = new Robot();
Robot robot2 = new Robot();
Robot robot3 = new Robot();
Assert.AreEqual(0, robot1.ID);
Assert.AreEqual(1, robot2.ID);
Assert.AreEqual(2, robot3.ID);
int expected = robot2.ID;
robot2.Dispose();
Robot robot4 = new Robot();
Assert.AreEqual(expected, robot4.ID);
}
不算完全是,但是你可以在类中使用静态整数,在构造函数被调用时将其初始化并递增。
class Robot()
{
static int nrOfInstances = 0;
init _id;
Robot()
{
_id = Robot.nrOfInstances;
Robot.nrOfInstances++;
}
}
如果你想重复使用一个已删除的机器人ID,不要使用计数器,而应使用静态列表并将其添加到列表中。
然而,更好的做法是将已使用的ID列表保留在另一个类中,这样就根本不需要使用静态。在使用静态之前,一定要三思而后行。你可以将已使用的ID列表保存在名为“RobotCreator”、“RobotHandler”、“RobotFactory”(不像设计模式)的类中。
没有这样的内置功能。你需要自己实现,例如持有一个位数组来标记已使用的id,然后每次创建新机器人时搜索第一个未使用的id。
顺便说一下,自增(在数据库中的意义上)实际上意味着即使先前使用过的一个或多个值不再与对象相关联,你仍然保持递增计数器。
这里是一些代码:
public class Robot
{
private static const int MAX_ROBOTS = 100;
private static bool[] usedIds = new bool[MAX_ROBOTS];
public int Id { get; set; }
public Robot()
{
this.Id = GetFirstUnused();
}
private static int GetFirstUnused()
{
int foundId = -1;
for(int i = 0; i < MAX_ROBOTS; i++)
{
if(usedIds[i] == false)
{
foundId = i;
usedIds[i] = true;
break;
}
}
return foundId;
}
}
有更复杂的算法/数据结构可以在小于O(N)的时间内找到第一个未使用的,但这超出了我的帖子范围。 :)
class Robot : IDisposable
{
static private int IdNext = 0;
static private int IdOfDestroy = -1;
public int RobotID
{
get;
private set;
}
public Robot()
{
if(IdOfDestroy == -1)
{
this.RobotID = Robot.IdNext;
Robot.IdNext++;
}
else
{
this.RobotID = Robot.IdOfDestroy;
}
}
public void Dispose()
{
Robot.IdOfDestroy = this.RobotID;
}
}
希望能对你有所帮助!
public static void beAddedTo<T>(this T item, Dictionary<int, T> dic) where T : m.lib.RandId
{
Random ran = new Random();
var ri = ran.Next();
while (Program.DB.Rooms.ContainsKey(ri)) ri = ran.Next();
item.Id = ri;
dic.Add(item.Id, item);
}
不是增量的,但你可以随意添加和删除项目。 (最大项目数量应低于 int.Max/2)