简体   繁体   English

C# 类自动递增 ID

[英]C# Class Auto increment ID

I am creating a class in C# called "Robot", and each robot requires a unique ID property which gives themselves an identity.我在 C# 中创建了一个名为“Robot”的类,每个机器人都需要一个唯一的 ID 属性,该属性赋予自己一个身份。

Is there any way of creating an auto incremental ID for each new class object?有没有办法为每个新的类对象创建一个自动增量 ID? So, If i created 5 new robots, their IDs respectively will be 1, 2, 3, 4, 5. If I then destroy robot 2 and create a new robot later, it will have the ID of 2. And if I add a 6th it will have the ID of 6 and so on..因此,如果我创建了 5 个新机器人,它们的 ID 分别为 1、2、3、4、5。如果我随后销毁机器人 2 并稍后创建一个新机器人,它的 ID 将为 2。如果我添加一个第 6 个它的 ID 为 6,依此类推..

Thanks.谢谢。

Create a static instance variable, and use Interlocked.Increment(ref nextId) on it.创建一个静态实例变量,并在其上使用Interlocked.Increment(ref nextId)

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

Note #1: using nextId++ would be valid only in non-concurrent environments;注意 #1:使用nextId++仅在非并发环境中有效; Interlocked.Increment works even if you allocate your robots from multiple threads.即使您从多个线程分配机器人, Interlocked.Increment也有效。

EDIT This does not deal with re-using robot IDs.编辑这不涉及重复使用机器人 ID。 If you need reuse, the solution is a lot more complex: you need a list of reusable IDs, and a ReaderWriterLockSlim around the code that accesses that list.如果您需要重用,则解决方案要复杂得多:您需要一个可重用 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();
    }
}

Note #2: If you would like to reuse smaller IDs ahead of larger IDs (as opposed to reusing IDs released earlier before IDs released later, as I coded it) you can replace IList<int> with SortedSet<int> and make a few adjustments around the parts where an ID to be reused is taken from the collection.注意#2:如果您想在较大 ID 之前重用较小的 ID(而不是重用在稍后发布的 ID 之前发布的 ID,正如我编码的那样),您可以将IList<int>替换为SortedSet<int>并制作一些围绕从集合中获取要重复使用的 ID 的部分进行调整。

This will do the trick, and operate in a nice threadsafe way.这将解决问题,并以一种不错的线程安全方式运行。 Of course it is up to you to dispose the robots yourself, etc. Obviously it won't be efficient for a large number of robots, but there are tons of ways to deal with that.当然,你可以自己处理机器人等。显然,对于大量机器人来说效率不高,但有很多方法可以解决这个问题。

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

And some test code for good measure.还有一些测试代码可以很好地衡量。

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

Not really, however you can use a static int which you initialize in the class and is incremented when the constructor is called.并非如此,但是您可以使用在类中初始化并在调用构造函数时递增的静态 int。

class Robot()
{
    static int nrOfInstances = 0;

    init _id;

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

(I hope the syntax is right, don't have a compiler here.) (我希望语法正确,这里没有编译器。)

If you want to have a removed robot ID being reused, don't use a counter, but use a static list and add it to the list.如果您希望重复使用已删除的机器人 ID,请不要使用计数器,而是使用静态列表并将其添加到列表中。

However, what might be better is to keep the list of used IDs in another class, so you don't need the static at all.但是,最好将已用 ID 的列表保存在另一个类中,这样您就根本不需要静态了。 Always think twice before you use a static.在使用静态之前务必三思而后行。 You might keep the list of used IDs in a class called 'RobotCreator', 'RobotHandler', 'RobotFactory' (not like the design pattern).您可以将使用的 ID 列表保存在名为“RobotCreator”、“RobotHandler”、“RobotFactory”的类中(不像设计模式)。

There is no such built-in functionality.没有这样的内置功能。 You have to implement it yourself, like holding an array of bits to mark the used ids and then searching for the first unused id every time you create a new robot.您必须自己实现它,例如保存一个位数组来标记已使用的 id,然后在每次创建新机器人时搜索第一个未使用的 id。

By the way, auto-increment (in a database sense) actually means that you keep incrementing the counter even if one or more of the previously used values are no longer associated to an object.顺便说一句,自动递增(在数据库意义上)实际上意味着即使一个或多个先前使用的值不再与对象关联,您也会继续递增计数器。

Here is some code:这是一些代码:

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

There are more sophisticated algorithms / data structures to find the first unused in less than O(N), but this is beyond the scope of my post.有更复杂的算法/数据结构可以在小于 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;
    }
}

I hope can help you !希望能帮到你!

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

Not incremental but you can add and delete item how many time you want.不是增量的,但您可以根据需要添加和删除项目多少次。 (Maximum item should be lower than int.Max/2) (最大项应低于 int.Max/2)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM