2014-12-04 3 views
3

Я пытаюсь создать список WeakReference с использованием обобщенной версии 4.5, чтобы я мог избежать проверки типов и литья цели WeakReference. Но WeakReference<T>, похоже, не поддерживает ковариацию, поэтому я пытаюсь установить обходной путь.Могу ли я создать список <WeakReference <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, но это, казалось бы, побеждало бы точку, так как я буду делать литье типов внутри нее. Я не могу найти какую-либо документацию, но я предполагаю, что версия фреймворка справляется с этим лучше.

Есть ли другой способ справиться с этим, о котором я не думаю, или я лаю неправильное дерево?

+0

'WeakReference ' не определяет общий параметр 'T' как ковариантный; вы можете добавить 'new WeakReference (новый Wolf())' в свою коллекцию. –

+0

Классы никогда не ковариантны; могут быть только интерфейсы и делегаты. И вообще, 'WeakReference ' не может быть ковариантным, так как 'T' отображается как в позиции ввода, так и на выходе. –

ответ

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

Теперь следующий вопрос, как его использовать? –

+0

@SriramSakthivel Это правильно в ответе. – Servy

+1

Нет, как использовать список? OP все равно будет получать 'Value' как« Animal »только в том случае, если список имеет тип IReadOnlyWeakReference . –

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