首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C#类自动增量ID

C#类自动增量ID
EN

Stack Overflow用户
提问于 2012-02-13 22:31:55
回答 6查看 57.5K关注 0票数 9

我在C#中创建了一个名为" robot“的类,每个机器人都需要一个唯一的ID属性,该属性为它们提供一个身份。

有没有办法为每个新的类对象创建一个自动增量ID?因此,如果我创建了5个新的机器人,它们的ID将分别是1、2、3、4、5。如果我销毁机器人2,然后创建一个新的机器人,它的ID将为2。如果我添加第6个,它的ID将为6,依此类推。

谢谢。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2012-02-13 22:54:15

这将会起作用,并以一种很好的threadsafe方式进行操作。当然,这取决于你自己来处理机器人,等等。显然,对于大量的机器人来说,这不是很有效,但有很多方法可以解决这个问题。

代码语言:javascript
复制
  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;
    }

和一些测试代码,以便更好地衡量。

代码语言:javascript
复制
[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);
}
票数 11
EN

Stack Overflow用户

发布于 2012-02-13 22:34:57

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

代码语言:javascript
复制
class Robot {
    static int nextId;
    public int RobotId {get; private set;}
    Robot() {
        RobotId = Interlocked.Increment(ref nextId);
    }
}

注意#1:使用nextId++仅在非并发环境中有效;即使您从多个线程分配robots,Interlocked.Increment也可以工作。

编辑这不涉及重复使用机器人ID。如果您需要重用,那么解决方案就复杂得多:您需要一个可重用ID的列表,以及访问该列表的代码周围的一个ReaderWriterLockSlim

代码语言:javascript
复制
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相反,正如我所编写的那样),您可以用SortedSet替换IList<int>,并围绕要重用的ID从集合中提取的部分进行一些调整。

票数 33
EN

Stack Overflow用户

发布于 2012-02-13 22:33:47

不是真的,但是你可以使用一个静态int,它是在类中初始化的,当构造函数被调用时会递增。

代码语言:javascript
复制
class Robot()
{
    static int nrOfInstances = 0;

    init _id;

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

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

如果您希望重用已删除的机器人ID,请不要使用计数器,而是使用静态列表并将其添加到列表中。

但是,更好的做法是将使用的ID列表保存在另一个类中,这样就完全不需要静态ID了。在使用静电之前一定要三思而后行。您可以将使用的ID列表保存在名为“RobotCreator”、“RobotHandler”、“RobotFactory”的类中(与设计模式不同)。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9262221

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档