14

私のクラスはIEnumerable<T>2 回実装します。毎回キャストせずにLINQを動作させるにはどうすればよいですか?hashtable


.NET の .NET からも継承する独自の共変ハッシュテーブル実装を作成しIDictionary<TKey, TValue>ました。最終的に、IEnumerable<T>の異なる型で 2 回実装しTます。プライマリの列挙可能なインターフェイスを暗黙的に実装し、もう一方を明示的に実装しました。このようなもの(疑似コード):

class HashTable<TKey, TValue> :
    ...
    IEnumerable<out IAssociation<out TKey, out TValue>>,
    IEnumerable<out KeyValuePair<TKey, TValue>>
{
    // Primary:
    public IEnumerator<IAssociation<TKey, TValue>> GetEnumerator();
    // Secondary:
    IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator();
}

foreachハッシュテーブルを取得すると、期待どおりに主要な列挙型が取得されます。

using System;
using System.Collections.Generic;
using System.Linq;

var hashtable = new HashTable<string, int>();
foreach (var kv in hashtable)
{
    // kv is IAssociation<string, int>
}

LINQ で同じことを実行したいのですが、拡張メソッドにどのインターフェイスを選択すればよいかわからないため、コンパイラ エラーが発生します。

var xs1 = from x in hashtable          // <-- 1
          select x;

var xs2 = hashtable.Select(x => x);    // <-- 2

エラー 1: ソース タイプ 'HashTable' のクエリ パターンの実装が見つかりませんでした。「選択」が見つかりません。範囲変数 'x' の型を明示的に指定することを検討してください。

エラー 2: 'HashTable' には 'Select' の定義が含まれておらず、タイプ 'HashTable' の最初の引数を受け入れる拡張メソッド 'Select' が見つかりませんでした (using ディレクティブまたはアセンブリ参照がありませんか?)

たぶん、私が知らないインターフェイスまたは継承のトリックがあるのでしょうか?


尋ねた人のために、インターフェースの完全なツリーは次のとおりです。

using SCG = System.Collections.Generic;

public class HashTable<TKey, TValue>
    : IKeyedCollection<TKey, TValue>, SCG.IDictionary<TKey, TValue>

public interface IKeyedCollection<out TKey, out TValue>
    : ICollection<IAssociation<TKey, TValue>>

public interface ICollection<out T> : SCG.IEnumerable<T>

public interface IAssociation<out TKey, out TValue>

// .NET Framework:
public interface IDictionary<TKey, TValue>
    : ICollection<KeyValuePair<TKey, TValue>>

public interface ICollection<T>
    : IEnumerable<T>

なぜ私が作れなかったのか、同じことがわかりKeyValuePair<TKey, TValue>ますIAssociation<TKey, TValue>

4

1 に答える 1

25

メソッド呼び出しの引数として式を使用する場合、コンパイラには「プライマリ」および「セカンダリ」インターフェイスの実装の概念がないことを理解することが重要です。それらのタイプへの変換に関する限り、あなたのタイプは両方IEnumerable<IAssociation<...>>を同様にうまく実装します。IEnumerable<KeyValuePair<...>>そのため、コンパイラーはより多くの情報を必要とします。

最も単純なアプローチ(IMO)は、2つの新しいプロパティを導入することです。

public IEnumerable<IAssociation<TKey, TValue>> Associations { get { return this; } }
public IEnumerable<KeyValuePair<TKey, TValue>> KeyValuePairs { get { return this; } }

つまり、簡単に具体的にすることができます。

var query = from x in table.Associations
            ...;

また

var query = from x in table.KeyValuePairs
            ...;

これは、コンパイラーを満足させるのに役立つだけでなく、コードを読み込もうとする人にも役立ちます。これらのいずれかを他よりもはるかに多くHashTable使用していることに気付いた場合は、常に1つだけを実装しIEumerable<>、他のプロパティを入力して保持することができます。

于 2013-02-14T15:41:40.947 に答える