我可以创建List <weakreference <t>&gt;?</weakreference <t>

时间:2014-12-04 18:33:43

标签: c# generics weak-references

我尝试使用4.5通用实现创建WeakReference列表,这样我就可以避免对WeakReference目标进行类型检查和转换。但是,WeakReference<T>似乎不支持协方差,所以我试图建立一种解决方法。

我认为它应该是可行的,因为每个T都是特定继承链中的类型。所以,我想的就是这些:

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()));

我已经尝试为WeakReference创建一个包装类(因为它不可继承),但这并不起作用。无论如何,该列表都不会接受WeakReference以外的任何类型WeakReference<Animal>

我可以创建自己的通用WeakReference实现,但这似乎是打败了这一点,因为我在其中进行类型转换。我无法找到任何文档,但我有点假设框架版本更好地处理这个问题。

还有另一种方法可以解决这个问题,我没想到,或者我是在咆哮错误的树?

3 个答案:

答案 0 :(得分:5)

WeakReference是不变的,因为它允许设置值,如果它是协变的则不会有效。为了使其协变,您需要围绕引用创建只读包装,并使用接口。

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);
        }
    }
}

转换的扩展方法也有点方便:

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

现在我们可以写:

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());

答案 1 :(得分:1)

我的建议是创建一个WeakReferences列表(List)并将其公开为IEnumerable,如下所示:

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));
    }
}

答案 2 :(得分:1)

您可以简单地使用WeakReference<Animal>本身,无论如何列表的类型为List<WeakReference<Animal>>,因此即使使用协方差,您也无法访问更多派生成员。

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()));

或者,如果您希望保留更具体的类型,则有一种方法。我之前用访客模式解决了这个问题。 See if that helps