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

I am trying to create a list WeakReference

using generic version 4.5 so that I can avoid type checking and target casting WeakReference

. But WeakReference<T>

doesn't seem to support covariance, so I'm trying to establish a workaround.

I think this should be doable as each T will have a type in a certain inheritance chain. So, I think it would be like this:

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 the WeakReference (since it doesn't inherit) but that doesn't work. No matter what the list will not accept any printed WeakReference

except WeakReference<Animal>

.

I could create my own generic implementation WeakReference

, but that would seem to defeat the point, since I will be doing type casting inside of it. I can't find any documentation, but my guess is that the framework version handles this better.

Is there another way to handle this that I don't think of, or am I barking the wrong tree?

+3


source to share


3 answers


WeakReference

is invariant since it allows a value to be set, and it is not valid if it were covariant. To make it covariant, you only need to create a readable wrapper around the link 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);
        }
    }
}

      

The extension method for conversion is also somewhat convenient:



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

      

We can now 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());

      

+5


source


My suggestion is to create a WeakReferences (List) and expose it as IEnumerable like this:



private List<WeakReference> innerList = new List<WeakReference>();

public IEnumerable<T> List
{
    get
    {
        return (this.innerList.Where(x => x.Target is T).Select(x => (T) x.Target));
    }
}

      

+1


source


You can just use it WeakReference<Animal>

yourself, anyways list is of type List<WeakReference<Animal>>

, so even with covariance you won't be able to access 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'd rather keep a more specific type, there is a way. I solved this earlier with the visitor template. See if this helps .

+1


source







All Articles