I am trying to understand ConditionalWeakTable. What is the difference between
class ClassA
{
static readonly ConditionalWeakTable<ClassA, OtherClass> OtherClassTable
= new ConditionalWeakTable<ClassA, OtherClass>();
}
and
class ClassB
{
OtherClass otherClass;
}
? What would be the pros and cons of using ClassA or ClassB to reference a nullable field?
The ConditionalWeakTable<TKey,TValue> class enables language compilers to attach arbitrary properties to managed objects at run time. A ConditionalWeakTable<TKey,TValue> object is a dictionary that binds a managed object, which is represented by a key, to its attached property, which is represented by a value.
A weak reference permits the garbage collector to collect the object while still allowing the application to access the object. A weak reference is valid only during the indeterminate amount of time until the object is collected when no strong references exist.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With