2012-11-18 26 views
0

我只是試圖在我的應用程序中使用System.Runtime.Serialization :: ObjectIDGenerator。我的應用程序需要與另一個進程進行通信。爲此,我需要在進程之間交換對象ID。 ObjectIDGenerator類似乎是解決方案...直到我發現有一個查找對象 - > ID但沒有查找ID - >對象。System.Runtime.Serialization :: ObjectIDGenerator

是否有更好的現成解決方案,允許在這兩個方向可靠和快速查找?

謝謝!

回答

1

ObjectIDGenerator只是在它看到的對象和分配的對象ID上保留一個散列表。

下面是一個簡化的版本在C#:

public class MyObjectIdGenerator 
{ 
    private Dictionary<int,List<int>> _hashToID = new Dictionary<int,List<int>>(); 
    private List<object> _objects = new List<object> { null, }; 
    private int _idCounter = 1; 
    private int _numRemoved = 0; 

    public int GetId(object obj) 
    { 
     if (obj == null) 
     { 
      return 0; 
     } 

     int hash = RuntimeHelpers.GetHashCode(obj); 

     List<int> ids; 
     if (!_hashToID.TryGetValue(hash, out ids)) 
     { 
      ids = new List<int>(); 
      _hashToID[hash] = ids; 
     } 

     foreach (var i in ids) 
     { 
      if (ReferenceEquals(_objects[i], obj)) 
      { 
       return i; 
      } 
     } 

     // Move the counter to the next free slot. 
     while (_idCounter < _objects.Count && _objects[_idCounter] != null) 
     { 
      _idCounter++; 
     } 

     int id = _idCounter++; 
     ids.Add(id); 

     // Extend the pool to enough slots. 
     while (_objects.Count <= id) { 
      _objects.Add(null); 
     } 
     _objects[id] = obj; 

     return id; 
    } 

    public bool Remove(object obj) 
    { 
     if (obj == null) return false; 

     // Locate the object 
     int hash = RuntimeHelpers.GetHashCode(obj); 
     List<int> ids; 
     if (!_hashToID.TryGetValue(hash, out ids)) return false; 

     foreach (var i in ids) 
     { 
      if (ReferenceEquals(_objects[i], obj)) 
      { 
       // Remove the object, and clean up. 
       _objects[i] = null; 
       ids.Remove(i); 
       if (ids.Count == 0) 
       { 
        _hashToID.Remove(hash); 
       } 
       _numRemoved++; 
       if (_numRemoved >= 10 && _numRemoved >= _objects.Count/2) { 
        // Too many free slots. Reset the counter. 
        _idCounter = 0; 
        _numRemoved = 0; 
       } 
       return true; 
      } 
     } 
     return false; 
    } 

    public object GetObject(int id) 
    { 
     if (id < 0 || id >= _objects.Count) return null; 
     // 0 => null 
     return _objects[id]; 
    } 
} 

下面是ObjectIDGenerator的反編譯的來源:http://www.fixee.org/paste/30e61ex/

編輯:添加Remove方法。

+0

順便說一句,如果不再需要在MyObjectIDGenerator中註冊的對象,會發生什麼? MyObjectIDGenerator通過持有引用來保持它們的生命,對吧?這是否阻止未使用的對象被垃圾收集? – Silicomancer

+1

這是正確的。標準的'ObjectIDGenerator'也可以保持對象的活動狀態。如果你需要這些對象是可收集的,你可以將每個對象包裝在一個'WeakReference'中。 –

+0

非常有趣。所以我肯定需要爲我的雙向查找對象ID生成器使用弱引用。如果我正確理解這些弱引用,我需要在使用引用之前檢查「IsAlive」。對?但是,這仍然意味着對象ID生成器會緩存弱引用,即使它是死的。這也意味着對象ID生成器的內部表將無限增長,即使大多數包含的引用已經死亡,對不對? – Silicomancer

相關問題