Archive for generics tag
Implementing a generic WeakReference<T> in C#
A weak reference lets you hold a reference to an object that will not prevent it from being garbage collected. There are a few scenarios where this might be important – such as listening for events, caching, various MVC patterns.
.NET and Java supports weak references with the aptly named WeakReference class. In .NET it exposes a .Target property of type object that weakly points to whatever you like.
Java also sports a generic WeakReference<T> to give you a strongly typed version so it’s somewhat puzzling why .NET doesn’t.
Here is my attempt at a WeakReference<T> for .NET. It works fine in the scenarios I’ve used and performance is close to the non-generic version but a quick glance at the SSCLI code for WeakReference reveals that the standard version is a little more complicated and it’s possible there is a reason for that – most likely due to finalizer issues.
using System;
using System.Runtime.InteropServices;
public class WeakReference<T> : IDisposable {
private GCHandle handle;
private bool trackResurrection;
public WeakReference(T target)
: this(target, false) {
}
public WeakReference(T target, bool trackResurrection) {
this.trackResurrection = trackResurrection;
this.Target = target;
}
~WeakReference() {
Dispose();
}
public void Dispose() {
handle.Free();
GC.SuppressFinalize(this);
}
public virtual bool IsAlive {
get { return (handle.Target != null); }
}
public virtual bool TrackResurrection {
get { return this.trackResurrection; }
}
public virtual T Target {
get {
object o = handle.Target;
if ((o == null) || (!(o is T)))
return default(T);
else
return (T)o;
}
set {
handle = GCHandle.Alloc(value,
this.trackResurrection ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak);
}
}
}
I’ve allowed Target to be settable against my better judgement to bring it more in like with WeakReference. It’s still not serializable though unlike WeakReference.
[)amien
Substitutability of generic types in .NET
The “is” operator
Anyone using object orientated programming soon finds themselves wanting to perform some action only if an object is of some type or implements some interface.
The easiest way is to do this is to use the “is” operator. Typically it will appear something like;
object objA = FunctionToGetAnObject();
if (obj is SomeClassOrInterface)
((SomeClassOrInterface) obj).SomeMethod();
Here if objA is of a type that implements SomeClassOrInterface anywhere in its inheritence tree then SomeMethod of SomeClassOrInterface will be called.
Test substitution with generic types
Now lets say we have our own generic type – here’s one to illustrate a point;
public class DamoClass<T> {
public T GetProperty { get { ... } }
public T SetProperty { set { ... } }
public bool IsValid { return true; }
}
If we want to check objA supports DamoClass<T> but we don’t care what type T is you might expect to be able to perform;
if (objA is DamoClass)
But that results in a compilation error – you can’t reference a generic class without specifying the type parameters regardless of whether you care about them or not. You might then try;
if (objA is DamoClass<object>)
After all every class inherits from object. This compiles fine but at runtime if objA is of any type other than object, e.g. DamoClass<string> it will return false.
Why?
The following might be what you had in mind;
if (objA is DamoClass<object>) {
((DamoClass<object>) objA).IsValid();
object test = ((DamoClass<object>) objA).GetProperty;
}
Which looks fine but if .NET allowed that then how would it prevent;
if (objA is DamoClass<object>)
((DamoClass<object>) objA).SetProperty = 11;
When objA.AssociatedObject might well be something other than an integer? It can’t – so it doesn’t.
Solution
The solution is to split your generic class into two classes.
The first contains your non-generic methods and properties and the second inherits from the first adding all the generic specialisation. The good news is that they can even have the same name.
public class DamoClass {
public object GetProperty { get { ... } }
public bool IsValid { return true; }
}
public class DamoClass<T> : DamoClass {
public T SetProperty { set { ... } }
}
Then you are free to do;
if (objA is DamoClass) {
((DamoClass) objA).IsValid();
object test = ((DamoClass) objA).GetProperty;
}
Indeed .NET itself uses this technique for IEnumerable and IEnumerable<T>
One drawback with this technique is that you can’t redefine the type of a member in the subclass – maybe that’ll make C# 3.0.
[)amien