Programing

IDictionary

lottogame 2020. 12. 13. 08:32
반응형

IDictionary .NET 4에서 공변이 아님


IDictionary<TKey, TValue>.NET 4 / 실버 라이트 4는 공분산을 지원하지 않는, 즉 내가 할 수 없어

IDictionary<string, object> myDict = new Dictionary<string, string>();

IEnumerable<T>지금 s로 할 수있는 것과 유사합니다 .

아마도 KeyValuePair<TKey, TValue>공변 적이 지 않기 때문일 것입니다. 적어도 값에 대해서는 사전에서 공분산이 허용되어야한다고 생각합니다.

그래서 그것은 버그입니까 아니면 기능입니까? 아마도 .NET 37.4에서 올 것인가?

업데이트 (2 년 후) :

거기에있을 것입니다 IReadOnlyDictionary<TKey, TValue>.NET 4.5하지만, 공변 될하거나하지 않습니다 :·/그것은에서 유래하기 때문에 IEnumerable<KeyValuePair<TKey, TValue>>, 그리고 KeyValuePair<TKey, TValue>공변 될 수 없습니다, 따라서 인터페이스하지 않고.

BCL 팀은 많은 것을 재 설계하고 ICovariantPair<TKey, TValue>대신 일부 사용해야 합니다. 또한 강력한 형식의 인덱서 this[TKey key]는 공변 인터페이스에 사용할 수 없습니다. 비슷한 목적은 GetValue<>(this IReadOnlyDictionary<TKey, TValue> self, TKey key)내부적으로 실제 구현을 호출해야하는 확장 메서드를 어딘가에 배치하는 방식으로 만 달성 할 수 있습니다 . 이는 매우 지저분한 접근 방식으로 보입니다.


기능입니다. .NET 4.0은 안전한 공분산 만 지원 합니다 . 언급 한 캐스트는 가능한 경우 사전에 문자열이 아닌 요소를 추가 할 수 있으므로 잠재적으로 위험합니다.

IDictionary<string, object> myDict = new Dictionary<string, string>();
myDict["hello"] = 5; // not an string

반면에는 IEnumerable<T>읽기 전용 인터페이스입니다. T유형의 매개 변수는 출력 위치 (의 반환 형식에 Current속성)가 치료하는 안전 그래서 IEnumerable<string>int로서 IEnumerable<object>.


하지만 당신은 말할 수 있습니다

myDict.Add("Hello, world!", new DateTime(2010, 1, 27));

비참하게 실패 할 것입니다. 문제는 입력이 입력 및 출력 위치 모두에서 사용 된다는 것 TValue입니다 IDictionary<TKey, TValue>. 재치 :

myDict.Add(key, value);   

TValue value = myDict[key];

그래서 그것은 버그입니까 아니면 기능입니까?

의도적으로 설계된 것입니다.

아마도 .NET 37.4에서 올 것인가?

아니요, 본질적으로 안전하지 않습니다.


비슷한 문제가 있었지만 더 전문화 된 파생 유형이 있습니다 (모든 것이 파생되는 객체보다는)

트릭은 메서드를 일반화하고 관련 제한을 두는 where 절을 넣는 것입니다. 기본 유형 및 파생 유형을 다루고 있다고 가정하면 다음이 작동합니다.

using System;
using System.Collections.Generic;

namespace GenericsTest
{
class Program
{
    static void Main(string[] args)
    {
        Program p = new Program();

        p.Run();
    }

    private void Run()
    {

        Dictionary<long, SpecialType1> a = new Dictionary<long, SpecialType1> {
        { 1, new SpecialType1 { BaseData = "hello", Special1 = 1 } },
        { 2, new SpecialType1 { BaseData = "goodbye", Special1 = 2 } } };

        Test(a);
    }

    void Test<Y>(Dictionary<long, Y> data) where Y : BaseType
    {
        foreach (BaseType x in data.Values)
        {
            Console.Out.WriteLine(x.BaseData);
        }
    }
}

public class BaseType
{
    public string BaseData { get; set; }
}

public class SpecialType1 : BaseType
{
    public int Special1 { get; set; }
}
}

.NET 4 만 지원 밖으로 공분산을하지 . IEnumerable은 읽기 전용이므로 IEnumerable과 함께 작동합니다.


특정 유형의 유용한 공분산에 대한 해결 방법 IDictionary

public static class DictionaryExtensions
{
    public static IReadOnlyDictionary<TKey, IEnumerable<TValue>> ToReadOnlyDictionary<TKey, TValue>(
        this IDictionary<TKey, List<TValue>> toWrap)
    {
        var intermediate = toWrap.ToDictionary(a => a.Key, a => a.Value!=null ? 
                                        a.Value.ToArray().AsEnumerable() : null);
        var wrapper = new ReadOnlyDictionary<TKey, IEnumerable<TValue>>(intermediate);
        return wrapper;
    }   
}

참고URL : https://stackoverflow.com/questions/2149589/idictionarytkey-tvalue-in-net-4-not-covariant

반응형