问题
I'm trying to create a List of WeakReference
s 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?
回答1:
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());
回答2:
My suggestion is to create a list of WeakReferences (List) and expose it as an 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));
}
}
回答3:
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.
来源:https://stackoverflow.com/questions/27301385/can-i-create-a-listweakreferencet