2012-02-13 5 views
5

C#에서 "Robot"이라는 클래스를 만들고 각 로봇마다 고유 한 ID 속성이 필요합니다.C# 클래스 자동 증가 ID

새 클래스 개체마다 자동 증분 ID를 만드는 방법이 있습니까? 그래서 5 개의 로봇을 만들었다면 ID는 각각 1, 2, 3, 4, 5가 될 것입니다. 로봇 2를 파괴하고 나중에 새로운 로봇을 만들면 ID 2가됩니다. 6 번째 ID는 6 등이됩니다.

고마워요.

+9

"로봇 2를 파괴하고 나중에 새 로봇을 만들면 ID 2가됩니다." 그것은 나에게 자동 증가의 기본 개념처럼 들리지 않는다. – BoltClock

+0

로봇 인스턴스가 일부 데이터 저장소에 유지됩니까? SQL Server, Access 등 – Bryan

답변

5

이것은 트릭을 수행하고 스레드 세이프 방식으로 작동합니다. 물론 로봇을 스스로 처분하는 것은 당신에게 달려 있습니다.분명히 많은 수의 로봇에게는 효율적이지 않지만 그 문제를 처리 할 수있는 방법은 수없이 많습니다.

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

이것은 훌륭했습니다! – rajcool111

2

그러나 실제로는 클래스에서 초기화하는 정적 int를 사용할 수 있으며 생성자가 호출 될 때 증가됩니다.

class Robot() 
{ 
    static int nrOfInstances = 0; 

    init _id; 

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

당신이 재사용되는 제거 로봇 ID를 원한다면 카운터를 사용하지 않는,

(나는. 여기에 컴파일러가없는, 구문이 바로 바랍니다)하지만를 사용 정적 목록에 추가하고 목록에 추가하십시오.

하지만 더 나은 방법은 사용 된 ID 목록을 다른 클래스에 보관하는 것입니다. 따라서 정적이 전혀 필요하지 않습니다. 정적을 사용하기 전에 항상 두 번 생각하십시오. 사용 된 ID 목록을 'RobotCreator', 'RobotHandler', 'RobotFactory'(디자인 패턴과 다름)라는 클래스에 보관할 수 있습니다.

24

정적 인스턴스 변수를 만들고 Interlocked.Increment(ref nextId)을 사용하십시오. 참고 번호 1 : nextId++을 사용하면 비 동시성 환경에서만 유효합니다. Interlocked.Increment은 여러 스레드에서 로봇을 할당하더라도 작동합니다.

EDIT 이것은 로봇 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를 다시하고 싶은 경우에 당신은 SortedSet<int>IList<int>을 대체하고 만들 수 있습니다 재사용 할 ID가 컬렉션에서 가져온 부품 주변의 조정은 거의 없습니다.

+1

단일 스레드 환경에서는 고전적인 증가만으로도 충분합니다. – Tudor

+3

거룩한 쓰레기! 나는 이것이 명백한 경쟁 조건을 다루는 유일한 대답이라고 믿을 수 없다. –

+1

@ Tudor :이 시대에는 단일 스레드 환경을 사용하는 즐거움이 없습니다. –

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

예상대로 작동하지 않습니다. 3 개의 로봇이 있다고 가정 해 봅시다. 처음에는 1, 2, 3의 ID를 사용합니다.이 순서대로 모든 것을 처리하면, 마지막으로 파괴 된 것은 없게됩니다. 3, 그래서 내가 만들 다음 로봇은 예상대로 1이 아니라 3이 될 것입니다. 사실,'IdOfDestroy'는 3을 유지할 것이므로 다음에 생성 된 로봇 역시 id가 3이됩니다. – Tudor

+0

예 @Tudor, 맞아요, 제 코드가 예상대로 작동하지 않아서 죄송합니다. 정말 고마워요. –

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보다 작아야합니다.)