2012-02-13 12 views
5

मैं "रोबोट" नामक सी # में एक कक्षा बना रहा हूं, और प्रत्येक रोबोट को एक अद्वितीय आईडी प्रॉपर्टी की आवश्यकता होती है जो स्वयं को पहचान देता है।सी # कक्षा ऑटो वृद्धि आईडी

क्या प्रत्येक नई कक्षा वस्तु के लिए ऑटो वृद्धिशील आईडी बनाने का कोई तरीका है? इसलिए, यदि मैंने 5 नए रोबोट बनाए हैं, तो उनकी आईडी क्रमशः 1, 2, 3, 4, 5 होगी। यदि मैं रोबोट 2 को नष्ट कर दूंगा और बाद में एक नया रोबोट बनाउंगा, तो इसमें 2 की आईडी होगी। और यदि मैं एक जोड़ता हूं 6 वें में 6 की आईडी होगी और इसी तरह ..

धन्यवाद।

+9

"यदि मैं रोबोट 2 को नष्ट करता हूं और बाद में एक नया रोबोट बनाता हूं, तो इसमें 2 की आईडी होगी।" यह मेरे लिए ऑटो-वृद्धि की मूल अवधारणा की तरह नहीं लगता है। – BoltClock

+0

क्या कुछ डेटा स्टोर में रोबोट के उदाहरण बने रहे हैं? एसक्यूएल सर्वर, एक्सेस, आदि – 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++; 
    } 
} 

(मुझे आशा है कि वाक्य रचना सही है, यहाँ एक संकलक नहीं है।)

आप पुन: उपयोग किया जा रहा है एक हटाया रोबोट आईडी होना चाहते हैं, एक काउंटर का उपयोग नहीं करते हैं, लेकिन एक का उपयोग स्थिर सूची और सूची में जोड़ें।

हालांकि, किसी अन्य वर्ग में प्रयुक्त आईडी की सूची रखने के लिए बेहतर क्या हो सकता है, इसलिए आपको स्थिर की आवश्यकता नहीं है। एक स्थैतिक उपयोग करने से पहले हमेशा दो बार सोचें। आप 'रोबोट क्रिएटर', 'रोबोट हैंडलर', 'रोबोट फैक्ट्री' (डिजाइन पैटर्न की तरह नहीं) नामक कक्षा में प्रयुक्त आईडी की सूची रख सकते हैं।

24

एक स्थिर आवृत्ति चर बनाएँ, और 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 काम करता है भले ही आप अपने रोबोट को एकाधिक धागे से आवंटित करते हैं।

EDIT यह रोबोट आईडी का पुन: उपयोग करने से संबंधित नहीं है। यदि आपको पुन: उपयोग की आवश्यकता है, तो समाधान बहुत अधिक जटिल है: आपको उस सूची तक पहुंचने वाले कोड के आस-पास पुन: प्रयोज्य आईडी की एक सूची और 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: आप आगे छोटे आईडी पुन: उपयोग करने बड़ा आईडी की (के रूप में बाद में जारी आईडी से पहले पहले जारी आईडी पुन: उपयोग करने का विरोध किया, के रूप में मैं इसे कोडित) चाहते हैं, तो आप IList<int>SortedSet<int> के साथ बदलें और एक कर सकते हैं उन हिस्सों के आस-पास कुछ समायोजन जहां एक आईडी का पुन: उपयोग किया जाना संग्रह से लिया जाता है।

+1

क्लासिक वृद्धि एक एकल थ्रेडेड वातावरण में पर्याप्त है। – Tudor

+3

पवित्र बकवास! मुझे विश्वास नहीं है कि यह एकमात्र उत्तर है जो स्पष्ट दौड़ की स्थिति को संबोधित करता है। –

+1

@ ट्यूडर: इस दिन और उम्र में हमें वास्तव में एक थ्रेडेड वातावरण को संभालने का आनंद नहीं मिलता है। –

2

ऐसी कोई अंतर्निहित कार्यक्षमता नहीं है। आपको इसे स्वयं लागू करना होगा, जैसे कि इस्तेमाल किए गए आईडी को चिह्नित करने के लिए बिट्स की एक सरणी पकड़ना और फिर जब आप एक नया रोबोट बनाते हैं तो पहले अप्रयुक्त आईडी की खोज करें।

वैसे, ऑटो-वृद्धि (डेटाबेस अर्थ में) वास्तव में इसका मतलब है कि आप काउंटर को बढ़ाना जारी रखते हैं भले ही पहले से उपयोग किए गए मानों में से एक या अधिक किसी ऑब्जेक्ट से जुड़े न हों।

यहाँ कुछ कोड है:

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

हे (एन) से भी कम में पहले अप्रयुक्त खोजने के लिए और अधिक परिष्कृत एल्गोरिदम/डाटा संरचनाओं हैं, लेकिन यह मेरी पोस्ट के दायरे से बाहर है। :)

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 के साथ। अगर मैं इन सभी को इस क्रम में निपटाना चाहता हूं, तो आखिरी नष्ट हो जाएगा। 3, तो मेरे द्वारा बनाए गए अगले रोबोट में आईडी 3 होगा, उम्मीद के अनुसार 1 नहीं। वास्तव में, 'IdOfDestroy' 3 रहेगा, इसलिए अगली बनाई गई रोबोट में आईडी भी होगी 3. – Tudor

+0

हाँ @ ट्यूडर, आप सही हैं, मुझे खेद है कि मेरा कोड अपेक्षित काम नहीं करेगा, आपको बहुत धन्यवाद। –

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 से कम होना चाहिए)

संबंधित मुद्दे