Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I create a List<WeakReference<T>>?

I'm trying to create a List of WeakReferences using the 4.5 generic implementation so that I can avoid type checking and casting of the WeakReference target. But, WeakReference<T> doesn't appear to support covariance, so I'm trying to establish a workaround.

I'm thinking it should be doable since each T would be of a type in a particular inheritance chain. So, what I'm thinking would be along these lines:

public class Animal { }
public class Tiger : Animal { }
public class Wolf : Animal { }

var mylist = new List<WeakReference<Animal>>();

mylist.Add(new WeakReference<Animal>(new Animal()));
mylist.Add(new WeakReference<Tiger>(new Tiger()));
mylist.Add(new WeakReference<Wolf>(new Wolf()));

I've tried creating a wrapper class for WeakReference (since it's non-inheritable), but that doesn't work. No matter what, the list won't accept any typed WeakReference other than WeakReference<Animal>.

I could create my own generic WeakReference implementation, but that would seem to be defeating the point since I'd be doing type casting within it. I can't find any documentation, but I'm kind of assuming the framework version handles this better.

Is there another way of handling this that I'm not thinking of, or am I barking up the wrong tree?

like image 946
Random Avatar asked Jan 10 '23 08:01

Random


2 Answers

WeakReference is invariant, since it allows the value to be set, and that wouldn't be valid if it were covariant. To make it covariant you'll need to make a read only wrapper around the reference, and also use an interface.

public interface IReadOnlyWeakReference<out T>
{
    T Value { get; }
}

public class WeakReferenceWrapper<T> : IReadOnlyWeakReference<T>
    where T : class
{
    private WeakReference<T> reference;
    public WeakReferenceWrapper(WeakReference<T> reference)
    {
        this.reference = reference;
    }

    public T Value
    {
        get
        {
            T output;
            if (reference.TryGetTarget(out output))
                return output;
            else
                return default(T);
        }
    }
}

An extension method for the conversion is also somewhat convenient:

public static IReadOnlyWeakReference<T> AsReadOnly<T>(
    this WeakReference<T> reference)
    where T : class
{
    return new WeakReferenceWrapper<T>(reference);
}

Now we can write:

var mylist = new List<IReadOnlyWeakReference<Animal>>();

mylist.Add(new WeakReference<Animal>(new Animal()).AsReadOnly());
mylist.Add(new WeakReference<Tiger>(new Tiger()).AsReadOnly());
mylist.Add(new WeakReference<Wolf>(new Wolf()).AsReadOnly());
like image 115
Servy Avatar answered Jan 15 '23 17:01

Servy


You could simply use WeakReference<Animal> itself, anyways list is of type List<WeakReference<Animal>>, so you even with the covariance, you'll not be able to access the more derived members.

var mylist = new List<WeakReference<Animal>>();    
mylist.Add(new WeakReference<Animal>(new Animal()));
mylist.Add(new WeakReference<Animal>(new Tiger()));
mylist.Add(new WeakReference<Animal>(new Wolf()));

Or if you prefer to keep the more specific type, there is a way. I've solved it earlier with visitor pattern. See if that helps.

like image 42
Sriram Sakthivel Avatar answered Jan 15 '23 16:01

Sriram Sakthivel