Understanding ConditionalWeakTable
I don't exactly get what you're asking about, I assume though you're asking whether you should use property inside your type or ConditionalWeakTable
, to which you can attach such a property for that particular type instance. If so, you could alternatively ask whether you should use property alone versus dictionary, which could contain this property under specific key (which will be your particular type instance). Unless you need such a dictionary, it's pretty nonsense.
Understanding of ConditionalWeakTable<TKey, TValue>
:
What ConditionalWeakTable
actually do is, it allows you to attach additional information to existing, managed, non-dynamic CLR objects. Essentially it can be understood just as a dictionary, where the keys are weakly referenced, so a value is kept alive as long as the key is alive. More information can be found on MSDN.
So, you should ask yourself what are your needs. Assuming your types are instantiated:
var classA = ClassA();
var classB = ClassB();
var other = OtherClass();
do you want to use the property binded to such instances in this manner:
/* set */
var other = new OtherClass();
ClassA.OtherClassTable.Add(classA, other);
/* get */
OtherClass data = null;
var result = ClassA.OtherClassTable.TryGetValue(classA, out data);
instead of this one below?
/* set */
classB.OtherClass = other;
/* get */
var result = classB.OtherClass;
Unless have particular needs, the answer seems to be pretty obvious. There are of course further issues here:
What is weak reference and why would you want to use it?
This MSDN article shortly explains the topic. It basically says weak references do not extend the lifetime of the object, by allowing it to be garbage collected, once such an object can still be reached by the application code. Weak references can be useful for pointing to objects which should be available for GC if they are not actively in use. However, if the program uses large number of small objects, weak references can negatively affect memory usage. Threads like this and this should also clarify some remaining doubts.
If you're looking for an example, when you could use ConditionalWeakTable<TKey, TValue>
over standard Dictionary<TKey, TValue>
, imagine the following case. You'd like to bind a dictionary of properties to an instance at runtime, but at the same time do not want to prevent them from being collected if you've stopped actively using them. Unfortunately in standard approach it's impossible - GC is blocked because dictionary still holds a strong references to them, like this:
var x = new object();
x.Props().Y = "hello";
static class ExpandoExtensions
{
private static IDictionary<object, dynamic> props =
new Dictionary<object, dynamic>();
public static dynamic Props(this object key)
{
dynamic o;
if (!props.TryGetValue(key, out o)){
o = new ExpandoObject();
props[key] = o;
}
return o;
}
}
Of course you can always take down them manually, but isn't this approach shown below simpler?
static class ExpandoExtensions
{
private static readonly ConditionalWeakTable<object, ExpandoObject> props =
new ConditionalWeakTable<object, ExpandoObject>();
public static dynamic Props(this object key)
{
return props.GetOrCreateValue(key);
}
}
At the same time (MSDN)
avoid using weak references as an automatic solution to memory management problems. Instead, develop an effective caching policy for handling your application's objects.
These extension methods shown above are taken from this thread.
One advantage to the first approach is that you can cache the instances of OtherClass
. For example,
class ClassA
{
static readonly ConditionalWeakTable<ClassA, OtherClass> OtherClassTable
= new ConditionalWeakTable<ClassA, OtherClass>();
public void Attach(OtherClass otherClass)
{
OtherClassTable.Add(this, otherClass);
}
public bool Get(out OtherClass otherClass)
{
return OtherClassTable.TryGetValue(this, out otherClass);
}
}
Then, you can attach an instance of OtherClass
to an instance of ClassA
. The instance of OtherClass
will be kept in memory as long as the instance of ClassA
to which it is attached is kept alive.
The biggest difference between the two--indeed, the primary reason that ConditionalWeakTable
exists and the reason it's part of CompilerServices
--is that adding a field to ClassA
requires the ability to add a field to ClassA
, but constructing a ConditionalWeakTable
with a key type of ClassA
does not. Effectively, ConditionalWeakTable
exists to allow code to effectively "add a field" to instances of any class without needing to modify the class itself. While it might in many cases be possible to use an identity-based weak-key dictionary for such a purpose, that would only work as long as no value held a direct or indirect reference to its key, and there were no cycles of keys which were referenced directly or directly via other key's values. The design of ConditionalWeakTable
allows keys and values to be collected even when such cycles exist.