0

現在 IDictionary<> を拡張するインターフェース (および Dictionary<> を拡張する実装) がありますが、エントリの追加または削除を許可しないこのインターフェースの実装が必要です (既存のエントリを変わったけど)。ReadOnlyCollection アプローチを採用して NotSupportedException をスローすることもできますが、これは少し間違っているように感じます。

代わりに、インターフェイスを分割して、アクセサー ビット用に 1 つ、ミューテーター ビット用に 1 つ用意しました。これを行うために、次のような結果になったことを除いて、これはすべて問題ありません(簡潔にするためにほとんどのメソッドを削除しました):

public interface IAccessor<TKey, TValue>
    {
    TValue this [TKey key] { get; set; }
    }

そして、私の元のインターフェースは次のようになりました。

public interface IAttributeDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IAccessor<TKey, TValue>
    {
    new TValue this [TKey key] { get; set; }
    }

そして、次のように定義された実装クラス:

public class AttributeDictionary<TKey,TValue>: Dictionary<TKey, TValue>, IAttributeDictionary<TKey, TValue> 

と のインデクサー間のあいまいさを避けるために、インデクサーを新しくする必要がIDictionaryありIAccessorました。ただし、実際の問題は、上のセッター インデクサーの動作がDictionary辞書に新しいエントリを作成することです。インターフェイスでエントリの変更のみを許可し、作成は許可しないようにしたいのでIAccessor、の実装で何をすべきAttributeDictionaryですか? 指定されたキーが辞書にあることを最初にチェックし、そうでない場合は例外をスローするインデクサーメソッドを明示的に実装する必要がIAccessorありますか、または異なる動作を持つ2つのインデクサーを持つことは悪い考えですか? IAccessorそれとも、インターフェイスのインデクサーを捨てて、代わりにGetValueandSetValueメソッドを使用して混乱を避けるべきですか?

4

1 に答える 1

1

問題は、まだ実装しようとしているということですIDictionary-そのインターフェイスを実装するべきではないと思いますAttributeDictionary(インターフェイスによって義務付けられているすべての機能を実際にサポートしていないため)。AttributeDictionaryただし、のインスタンスを取得するメソッドに送信する必要がありIDictionary、実装チェーンの上位にIDictionary使用できるインターフェイスがないためにサポートする必要がある場合は、次善の策は単純にIDictionary単独で実装してスローすることだと思いますインデクサーのセッター。

あなたが今試みているアプローチは、特にインターフェイス自体を介してクラスのインスタンスを操作する場合に、実際に知らないうちに間違ったインデクサーを呼び出すという微妙なバグにつながると思います。

編集:この回答に対するサムの最初のコメントの後:

次のようなアプローチはどうでしょうか。

public interface IAccessor<K,V> {
    V this[K key] { get; }
}

public interface IAttributeDictionary<K,V> : IAccessor<K,V>, IDictionary<K,V> {
    // This interface just composes the other two.
}

public class Test<K,V> : IAttributeDictionary<K,V> {
    // This will implement the indexer for both IAccessor and IDictionary.
    // But when the object is accessed as an IAccessor the setter is not available.
    public V this[K key] {
        get { Console.WriteLine("getter"); return default(V); }
        set { Console.WriteLine("setter"); }
    }

    // ...the rest of IDictionary goes here...
}

class Program {
    static void Main (string[] args) {
        // Note that test can be accessed as any of the appropriate types,
        // and the same getter is called.
        Test<string,int> test = new Test<string, int>();
        int a = test["a"];
        int b = ((IDictionary<string, int>)test)["b"];
        int c = ((IAccessor<string, int>)test)["c"];
    }
}

編集 2.0: 以下のコメントでのすべての議論の後、私は最終的に問題を理解するかもしれないと思うので...

IAccessor(私の意見では)インデクサーから必要な動作は非常に珍しく、予期しないものであるため、実際にはインデクサーを使用すべきではないと主張します。代わりに、必要な動作を提供できるGetValueForKeyand ChangeValueForKeyonを使用し、具体的な実装クラスIAccessorからインデクサーを実装します。IDictionary何らかの理由でそれが受け入れられない場合は、明示的なインターフェイス実装を使用して実装IAccessorし、実装クラスでそのインデクサーを使用することをお勧めします。どちらの場合も、新しい宣言は必要ないと思いますIAttributeDictionary

于 2011-01-13T16:54:24.423 に答える