作为某些IPC框架的一部分,服务器端代码实现了整数到对象的映射(这样IPC消息可以使用整数来引用对象)。
映射不直接将引用存储到对象,而是存储到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
实现包装的任何对象持有强引用吗?
答案 0 :(得分:1)
也许你可以添加另一层抽象:)
class WeakGUIObject : IGUIObject
{
WeakReference wr;
public WindowsFormsControl( IGUIObject inner )
{
wr = new WR(inner);
}
public virtual Rectangle Bounds
{
get
{
var inner = wr.Target;
if (inner == null) throw ObjectDisposedException();
return inner.Bounds;
}
}
}
现在,您可以进行字典引用并分发WeakGUIObject
个实例。这会自动使所有代理对象变弱。
不确定整个设计是个好主意。 ObjectDict
的客户可能会发现他们的对象随机消失并开始投掷。但这似乎是你的目标。