30

読み取り専用インターフェイスを持つオブジェクトを保持する読み取り専用ディクショナリを公開しようとしています。内部的には、ディクショナリは書き込み可能であり、内部のオブジェクトも書き込み可能です (以下のコード例を参照)。私の問題は、質問here で概説されている理由により、 IReadOnlyDictionary が共変変換をサポートしていないことです。つまり、内部辞書を読み取り専用として公開することはできません。

私の質問は、内部辞書を IReadOnlyDictionary に変換する効率的な方法、またはこれを処理する他の方法はありますか? 私が考えることができるオプションは次のとおりです。

  1. 2 つの内部辞書を保持し、それらを同期させます。
  2. プロパティがアクセスされたときに新しいディクショナリを作成し、その中のすべてのオブジェクトをキャストします。
  3. 内部で使用する場合は、IReadOnly を NotReadOnly にキャストします。

1 は面倒に思えますが、2 は非常に非効率的です。現時点では 3 が最も有望なように思えますが、まだ見苦しいです。他に選択肢はありますか?

public class ExposesReadOnly
{
    private Dictionary<int, NotReadOnly> InternalDict { get; set; }
    public IReadOnlyDictionary<int, IReadOnly> PublicList
    {
        get
        {
            // This doesn't work...
            return this.InternalDict;
        }
    }

    // This class can be modified internally, but I don't want
    // to expose this functionality.
    private class NotReadOnly : IReadOnly
    {
        public string Name { get; set; }
    }
}

public interface IReadOnly
{
    string Name { get; }
}
4

5 に答える 5

23

辞書用の独自の読み取り専用ラッパーを作成できます。たとえば、次のようになります。

public class ReadOnlyDictionaryWrapper<TKey, TValue, TReadOnlyValue> : IReadOnlyDictionary<TKey, TReadOnlyValue> where TValue : TReadOnlyValue
{
    private IDictionary<TKey, TValue> _dictionary;

    public ReadOnlyDictionaryWrapper(IDictionary<TKey, TValue> dictionary)
    {
        if (dictionary == null) throw new ArgumentNullException("dictionary");
        _dictionary = dictionary;
    }
    public bool ContainsKey(TKey key) { return _dictionary.ContainsKey(key); }

    public IEnumerable<TKey> Keys { get { return _dictionary.Keys; } }

    public bool TryGetValue(TKey key, out TReadOnlyValue value)
    {
        TValue v;
        var result = _dictionary.TryGetValue(key, out v);
        value = v;
        return result;
    }

    public IEnumerable<TReadOnlyValue> Values { get { return _dictionary.Values.Cast<TReadOnlyValue>(); } }

    public TReadOnlyValue this[TKey key] { get { return _dictionary[key]; } }

    public int Count { get { return _dictionary.Count; } }

    public IEnumerator<KeyValuePair<TKey, TReadOnlyValue>> GetEnumerator()
    {
        return _dictionary
                    .Select(x => new KeyValuePair<TKey, TReadOnlyValue>(x.Key, x.Value))
                    .GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}
于 2012-11-28T10:29:08.753 に答える
1

独自の共変インターフェイスを定義し、共変アクセス メソッドと、IDictionaryまたはIReadonlyDictionary目的の型を実装する読み取り専用ラッパー オブジェクトを作成するメソッドを含めることをお勧めします。IEnumerable<KeyValuePair<TKey,TValue>>インターフェース内で単に無視してください。

何をしているかによっては、IFetchByKey<out TValue>によって継承されるを定義すると役立つ場合があります。IFetchByKey<in TKey, out TValue>前者は、任意のタイプのオブジェクトのクエリを受け入れます (オブジェクト インスタンスが与えられた場合、 のコレクションは、Catそのインスタンスが含まれているかどうかを判断できる必要があります。型DogまたはであってもToyotaPrius、コレクションには後者の型のインスタンスは含まれず、そう言えるはずです)。

于 2012-12-03T17:51:47.097 に答える
0

多分この解決策はあなたのために働くでしょう:

public class ExposesReadOnly
{
    private IDictionary<int, IReadOnly> InternalDict { get; set; }
    public IReadOnlyDictionary<int, IReadOnly> PublicList
    {
        get
        {
            IReadOnlyDictionary<int, IReadOnly> dictionary = new ReadOnlyDictionary<int, IReadOnly>(InternalDict);

            return dictionary;
        }
    }

    private class NotReadOnly : IReadOnly
    {
        public string Name { get; set; }
    }

    public void AddSomeValue()
    {
        InternalDict = new Dictionary<int, NotReadOnly>();
        InternalDict.Add(1, new NotReadOnly() { Name = "SomeValue" });
    }
}

public interface IReadOnly
{
    string Name { get; }
}

class Program
{
    static void Main(string[] args)
    {
        ExposesReadOnly exposesReadOnly = new ExposesReadOnly();
        exposesReadOnly.AddSomeValue();

        Console.WriteLine(exposesReadOnly.PublicList[1].Name);
        Console.ReadLine();

        exposesReadOnly.PublicList[1].Name = "This is not possible!";
    }
}

お役に立てれば!

あいさつ

于 2012-11-27T22:28:30.190 に答える