作为IPC框架的一部分,服务器端代码实现了整数到对象的映射(以便IPC消息可以使用整数引用对象)。
但是,该映射不直接存储到对象的引用,而是存储到IGUIObject实现,此接口由代理对象实现,这些代理对象包装实际对象。也就是说,有一个类似于下面的接口:
映射类是一个单例,它的样子如下:
问题在于,
然而,
但是,该映射不直接存储到对象的引用,而是存储到IGUIObject实现,此接口由代理对象实现,这些代理对象包装实际对象。也就是说,有一个类似于下面的接口:
interface IGUIObject
{
Rectangle Bounds { get; }
}
然后可能有一些实现方式,比如
class WindowsFormsControl : IGUIObject
{
private Control m_control;
public WindowsFormsControl( Control control )
{
m_control = control;
}
public virtual Rectangle Bounds
{
get
{
return m_control.Bounds;
}
}
}
映射类是一个单例,它的样子如下:
class ObjectDict
{
private static readonly ObjectDict s_instance = new ObjectDict();
private Dictionary<int, IGUIObject> m_idToObjectDict;
private Dictionary<IGUIObject, int> m_objectToIdDict;
private int m_lastObjectId;
public static ObjectDict Instance
{
get
{
return s_instance;
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
public IGUIObject objectForId( int id )
{
IGUIObject go;
if ( m_idToObjectDict.TryGetValue( id, out go ) ) {
return go;
}
return null;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public int idForObject( IGUIObject go )
{
// Lookup ID for objects, register object and return new ID if needed
}
// ...
}
问题在于,
ObjectDict
类不应该阻止应用程序对象被垃圾回收,即应该保持弱引用,在这种情况下,ObjectDict.objectForId
应该抛出异常。然而,
在
IGUIObject
实现中使用弱引用似乎没有帮助,因为ObjectDict
类是包装器对象的所有者。它们没有其他存储位置。只有在IPC系统接收到显式的“释放ID为12345的对象”消息时,才会从字典中删除包装器对象。我需要解决的问题是代理对象可能被垃圾回收,我想允许、检测和优雅地处理它。包装器对象应该与代理对象一样长寿(潜在地更长),但不能更短。让
WindowsFormsExtension
持有Control
对象的弱引用,然后让ObjectCache
持有IGUIObject
实现的弱引用也没有帮助,因为代理对象(即WindowsFormsControl
)并不反映所包含对象的“null-ness”。另一个复杂因素是,有许多(几十个)IGUIObject
接口的实现,但只有一个ObjectDict
类。因此,任何不需要我调整所有IGUIObject
实现以开始使用弱引用的繁琐和容易出错的解决方案都更受欢迎。
ObjectDict
不(间接)保持对IGUIObject
实现包装的任何对象的强引用吗?
ObjectDict
确实 是包装对象的所有者,即它不能持有对它们的弱引用。只要IPC系统没有显式发送“释放”消息将它们从字典中删除,包装对象就会一直存在。但是,代理对象可能已经消失了(它肯定应该被允许这样做!),我希望能够优雅地处理这种情况。 - Frerich RaabeDictionary<int, WeakReference<IGUIObject>>
呢? - vgruIGUIObject
实现。 - Frerich Raabe