7

このスレッドでは

キーでディクショナリ値にアクセスする KeyNotFoundException の代わりに null を取得する方法は?

私自身の答えでは、明示的なインターフェイス実装を使用してKeyNotFoundException、キーが辞書に存在しない場合にスローしない基本的な辞書インデクサーの動作を変更しました(nullそのような場合、インラインで取得するのが便利だったため)。

ここにあります:

public interface INullValueDictionary<T, U>
    where U : class
{
    U this[T key] { get; }
}

public class NullValueDictionary<T, U> : Dictionary<T, U>, INullValueDictionary<T, U>
    where U : class
{
    U INullValueDictionary<T, U>.this[T key]
    {
        get
        {
            if (ContainsKey(key))
                return this[key];
            else
                return null;
        }
    }
}

実際のアプリケーションでは辞書のリストがあったため、インターフェイスとしてコレクションから辞書にアクセスする方法が必要でした。リストの各要素にアクセスするために単純なintインデクサーを使用しました。

var list = new List<NullValueDictionary<string, string>>();
int index = 0;
//...
list[index]["somekey"] = "somevalue";

最も簡単なことは、次のようなことをすることでした:

var idict = (INullValueDictionary<string, string>)list[index];
string value = idict["somekey"];

共分散機能を使用して、代わりに使用するインターフェイスのコレクションを使用しようと決めたときに発生した質問。そのため、キャストを機能させるには、共変型パラメーターを持つインターフェイスが必要でした。最初に頭に浮かんだのは だったIEnumerable<T>ので、コードは次のようになります。

IEnumerable<INullValueDictionary<string, string>> ilist = list;
string value = ilist.ElementAt(index)["somekey"];

ElementAtインデクサーの代わりに、はるかに悪いことに加えて、それほど良いことではありません。のインデクサーList<T>は で定義されておりIList<T>T共変ではありません。

私は何をすべきでしたか?私は自分で書くことにしました:

public interface IIndexedEnumerable<out T>
{
    T this[int index] { get; }
}

public class ExtendedList<T> : List<T>, IIndexedEnumerable<T>
{

}

まあ、数行のコード (私は何も書く必要さえありませんExtendedList<T>)、そしてそれは私が望んでいたように動作します:

var elist = new ExtendedList<NullValueDictionary<string, string>>();
IIndexedEnumerable<INullValueDictionary<string, string>> ielist = elist;
int index = 0;
//...
elist[index]["somekey"] = "somevalue";
string value = ielist[index]["somekey"];

最後に、追加のコレクションを作成せずに、この共変キャストを何らかの形で実現できるかという問題があります。

4

1 に答える 1

7

IReadOnlyList<T>によって実装されているを使用してみることができますList<T>

のインスタンスを1つ追加NullValueDictionary<string, string>したので、列に並ぶことはありませListん。ArgumentOutOfRangeExceptionelist[index]

IReadOnlyList<NullValueDictionary<string, string>> elist = new List<NullValueDictionary<string, string>>
                                                                    { 
                                                                        new NullValueDictionary<string, string>() 
                                                                    };
IReadOnlyList<INullValueDictionary<string, string>> ielist = elist;

int index = 0;
//...
elist[index]["somekey"] = "somevalue";
string value = elist[index]["somekey"];

編集: .NET 4.5より前のインデックスを持つ共変インターフェイスとコレクションを検索しましたが、見つかりませんでした。それでも、別のインターフェイスを作成するよりも、コレクションを別のコレクションにキャストするよりも、少し簡単な解決策があると思います。

List<INullValueDictionary<string, string>> ielist = elist.Cast<INullValueDictionary<string, string>>().ToList();

または、配列から得られた共分散を使用します

INullValueDictionary<string, string>[] ielist = elist.ToArray()

LINQには、型全体の互換性に対応する最適化機能があるため、これらの型に互換性がある場合は、シーケンスを繰り返す必要はありません。

MONOLinqから取得したキャストの実装

public static IEnumerable<TResult> Cast<TResult> (this IEnumerable source)
{
    var actual = source as IEnumerable<TResult>;
    if (actual != null)
        return actual;

    return CreateCastIterator<TResult> (source);
}

動作するように、プロパティINullValueDictionary<T, U>に含めるようにインターフェイスを変更したことに注意してください。setielist[index]["somekey"] = "somevalue";

public interface INullValueDictionary<T, U> where U : class
{
    U this[T key] { get; set; }
}

しかし、繰り返しになりますが、新しいインターフェイスとクラスを作成しても問題がなく、どこでもキャストをいじりたくない場合は、制約を考慮した場合、それは良い解決策だと思います。

mscorlibの共分散を求めて

これはおそらくあなたにとって興味深いことではありませんが、mscorlibアセンブリでどのタイプが共変であるかを知りたいだけです。次のスクリプトを実行することにより、17種類のみが共変であり、そのうち9種類はFuncsです。IsCovariantこの答えはそれがなくても長すぎるので、私は実装を省略しました

typeof(int).Assembly.GetTypes()
                    .Where(type => type.IsGenericType)
                    .Where(type=>type.GetGenericArguments().Any(IsCovariant))
                    .Select(type => type.Name)
                    .Dump();

//Converter`2 
//IEnumerator`1 
//IEnumerable`1 
//IReadOnlyCollection`1 
//IReadOnlyList`1 
//IObservable`1 
//Indexer_Get_Delegate`1 
//GetEnumerator_Delegate`1 
于 2013-01-04T09:44:17.350 に答える