C#类自动增量ID

问题描述 投票:8回答:6

我创造了被称为“机器人” C#类,每个机器人需要一个唯一的ID属性,它给出了自己的身份。

有没有为每一个新的类对象创建一个自动增量ID的方法吗?所以,如果我创建5个新的机器人,它们的ID分别为1,2,3,4,5,如果我然后破坏机器人2和后创建新的机器人,它将具有的背景ID如果我添加6日将有6 ID等..

谢谢。

c# class identity auto-increment member
6个回答
11
投票

这将这样的伎俩,并在一个不错的线程的方式运行。当然,这是你自己处置的机器人等。显然它不会是有效的对大量的机器人,但也有吨的方式来面对这一切。

  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);
}

28
投票

创建一个静态实例变量,并在其上使用Interlocked.Increment(ref nextId)

class Robot {
    static int nextId;
    public int RobotId {get; private set;}
    Robot() {
        RobotId = Interlocked.Increment(ref nextId);
    }
}

注1:使用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从集合取。


2
投票

不是真的,但是你可以使用你的类初始化,当调用构造函数递增静态INT。

class Robot()
{
    static int nrOfInstances = 0;

    init _id;

    Robot()
    {
        _id = Robot.nrOfInstances;
        Robot.nrOfInstances++;
    }
}

(我希望的语法是正确的,没有一个编译器在这里。)

如果你想有被重用的去除机器人ID,不使用计数器,而是使用一个静态列表,并将其添加到列表中。

然而,哪些最好是保持使用的ID名单中的另一个类,所以你不需要静态的。凡事三思而后你使用静态前。你可能会继续使用的ID名单中的一个名为“RobotCreator”,“RobotHandler”,“RobotFactory”类(不喜欢的设计模式)。


2
投票

有没有这样的内置功能。你必须自己实现它,就像抱着一组位来标记使用的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 = usedIds[i];
                 usedIds[i] = true;
                 break;
             }
         }
         return foundId;
    }
}

还有更复杂的算法/数据结构来查找不到O(N)的第一个未使用,但是这超出了我的职务范围。 :)


1
投票
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;
    }
}

希望可以帮到你!


0
投票
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下)

© www.soinside.com 2019 - 2024. All rights reserved.