KeyValuePair Covariance

本文关键字:Covariance KeyValuePair | 更新日期: 2023-09-27 17:59:44

在这个例子中有更好的方法来模拟协方差吗?理想情况下,我想做:

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

但CCD_ 1不是协变的。

相反,我必须做:

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

有更好/更干净的方法吗?

KeyValuePair Covariance

不幸的是,KeyValuePair<TKey, TValue>是一个结构;并且structs在中不表现出变化。NET。

当然,您可以通过编写自己的协变Pair接口和一些简单的助手来解决这个问题,以便在KeyValuePair序列和自定义Pair接口之间进行转换。这会让你做:

var dict = new Dictionary<string, ICollection<string>>();
var view = dict.GetCovariantView(); // IEnumerable< IPair<string, ICollection<string> > >
  
// Notice that you can _widen_ both the key and the value types:
var dictView = view.CastPairs<object, IEnumerable<string>>(); // IEnumerable< IPair< object, IEnumerable<String> > >
// The `CastPairs` call is actually unnecessary provided you don't use `var` for the left-hand-side assignment.
// ...this is due to the implicit (and identity-preserving) variant interface conversion in C#, e.g.:
IEnumerable< IPair< Object, IEnumerable<String> > > dictView2 = view;
Console.WriteLine( Object.ReferenceEquals( view, dictView2 ) ); // --> True

这里有一些示例代码可以让你实现这一点:

// `out TKey` is for demonstration purposes. In production-quality code you probably should be using invariant key types.
public interface IPair<out TKey, out TValue>
    where TKey : notnull
{
    TKey   Key   { get; }
    TValue Value { get; }
}
public class Pair<TKey, TValue> : IPair<TKey, TValue>
    where TKey : notnull
{
    public TKey   Key   { get; }
    public TValue Value { get; }
    public Pair(TKey key, TValue value)
    {
        this.Key   = key;
        this.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)
        where TKey : notnull
    {
        if (source is null) throw new ArgumentNullException(nameof(source));
        return source.Select(kvp => new Pair<TKey, TValue>(kvp));
    }
    public static IEnumerable<IPair<TKey, TValue>> CastPairs<TKey, TValue>(this IEnumerable<IPair<TKey, TValue>> source)
        where TKey : notnull
    {
        if (source is null) throw new ArgumentNullException(nameof(source));
        return source;
    }
}

几乎没有。KVP是一个结构:不是itnerface,而是ValueType。

有趣的SO关于差异的帖子。

我认为转换更具性能,所以我更喜欢这样编码:

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

在我真正需要的地方把KeyValuePair.Value转换成ICollection。坦率地说,这取决于foos的使用方式。