2013-02-16 10 views
9

Czy istnieje lepszy sposób naśladowania kowariancji w tym przykładzie? Idealnie chciałabym zrobić:KeyValuePair Covariance

private IDictionary<string, ICollection<string>> foos; 

public IEnumerable<KeyValuePair<string, IEnumerable<string>> Foos 
{ 
    get 
    { 
     return foos; 
    } 
} 

Ale KeyValuePair<TKey, TValue> nie jest kowariantna.

Zamiast muszę zrobić:

public IEnumerable<KeyValuePair<string, IEnumerable<string>>> Foos 
{ 
    get 
    { 
     return foos.Select(x => 
      new KeyValuePair<string, IEnumerable<string>>(x.Key, x.Value)); 
    } 
} 

Czy jest lepiej/bardziej przejrzysty sposób?

Odpowiedz

5

Niestety, KeyValuePair<TKey, TValue> jest strukturą; i structs nie wykazują wariancji w .NET.

Można oczywiście rozwiązać ten problem, pisząc własny interfejs covariant Pair i kilka prostych pomocników, aby przekonwertować sekwencje KeyValuePair i niestandardowego interfejsu Pair. Pozwoli Ci to zrobić:

var dict = new Dictionary<string, ICollection<string>>(); 

// Notice that you can "weaken" both the key and the value. 
var dictView = dict.GetCovariantView() 
        .CastPairs<object, IEnumerable<string>>(); 

Oto niektóre przykładowy kod, który pozwoli Ci osiągnąć ten cel:

public interface IPair<out TKey, out TValue> 
{ 
    TKey Key { get; } 
    TValue Value { get; } 
} 

public class Pair<TKey, TValue> : IPair<TKey, TValue> 
{ 
    public TKey Key { get; private set; } 
    public TValue Value { get; private set; } 

    public Pair(TKey key, TValue value) 
    { 
     Key = key; 
     Value = value; 
    } 

    public Pair(KeyValuePair<TKey, TValue> pair) 
     : this(pair.Key, pair.Value) { } 
} 

public static class PairSequenceExtensions 
{ 
    public static IEnumerable<IPair<TKey, TValue>> GetCovariantView<TKey, TValue> 
      (this IEnumerable<KeyValuePair<TKey, TValue>> source) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 

     return source.Select(pair => new Pair<TKey, TValue>(pair)); 
    } 

    public static IEnumerable<IPair<TKey, TValue>> CastPairs<TKey, TValue> 
     (this IEnumerable<IPair<TKey, TValue>> source) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 

     return source; 
    } 
} 
0

Prawie. KVP to struct: Not a iterface, jest ValueType.

Interesujące SO post o wariancji.

myślę odlewy są bardziej wydajnych, więc wolałbym kodu:

private IDictionary<string, IEnumerable<string>> foos; 

public IEnumerable<KeyValuePair<string, IEnumerable<string>> Foos 
{ 
    get 
    { 
     return foos; 
    } 
} 

i odlewane KeyValuePair.Value do ICollection gdzie naprawdę trzeba. Szczerze mówiąc zależy to od tego, jak używane są foos.