C#类自增ID

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9262221/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 06:36:55  来源:igfitidea点击:

C# Class Auto increment ID

c#classidentityauto-incrementmember

提问by Stefan Dunn

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? 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..

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

Thanks.

谢谢。

采纳答案by A.R.

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

回答by Michel Keijzers

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. 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 列表保留在另一个类中,这样您就根本不需要静态。在使用静态之前,请务必三思。您可以将使用的 ID 列表保存在名为“RobotCreator”、“RobotHandler”、“RobotFactory”的类中(与设计模式不同)。

回答by dasblinkenlight

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; Interlocked.Incrementworks even if you allocate your robots from multiple threads.

注意#1: usingnextId++仅在非并发环境中有效;Interlocked.Increment即使您从多个线程分配机器人也能工作。

EDITThis does not deal with re-using robot IDs. If you need reuse, the solution is a lot more complex: you need a list of reusable IDs, and a ReaderWriterLockSlimaround the code that accesses that list.

编辑这不涉及重复使用机器人 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();
    }
}

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被重用是从集合中取出的。

回答by Tudor

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 = usedIds[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) 的时间内找到第一个未使用的,但这超出了我的帖子的范围。:)

回答by Ruiqiang Liu

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 !

希望能帮到你!

回答by Kaiba Zax

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)