7

のプロパティであるDictionary<int, object> ところがあります。このためのより良いデータ構造はありますか?キーが冗長なので、プロパティを使用したい気がします。intobj

これは、 ID番号に基づいDictionary<int, obj>て値にランダムにインデックスを付けることができるコンテナクラスのフィールドです。コンテナクラスの簡略化された(例外処理なしの)インデクサーは次のようになります。objint

obj this[int id]
{
     get{ return this.myDictionary[id];}
}

ここで、オブジェクトを保持するmyDictionary前述のです。Dictionary<int, obj>

これは迅速なランダムアクセスの典型的な方法かもしれませんが、私はセカンドオピニオンを得たいと思いました。

4

4 に答える 4

9

KeyedCollectionクラスがあります。

編集:KeyedCollectionは内部で辞書を使用できますが、値で直接検索できるため、生の辞書よりもこの特定のシナリオのインターフェイスがクリーンになります。確かに、私はそれが一般的にあまり有用であるとは思いません。

于 2010-01-28T12:41:21.630 に答える
9

これを行うフレームワークには具体的なクラスはありません。ただし、KeyedCollectionという抽象的なものがあります。そのクラスから独自のクラスを派生させ、GetKeyForItem()メソッドを実装する必要があります。これは非常に簡単です。インデックスを作成するプロパティの値を返すだけです。

必要なのはこれだけですが、ChangeItemKey()に注意してください。キーとして使用するプロパティの値が変わる場合は、何か意味のあることをする必要があります。プロパティが不変であることを確認すれば、十分に簡単です(ゲッターのみがあります)。ただし、そうでない場合は非常に厄介です。オブジェクト自体が、コレクションに格納されていることを認識する必要があります。それについて何もしなければ(ChangeItemKeyを呼び出す)、オブジェクトはコレクション内で失われ、元に戻すことはできません。リークにかなり近い。

Dictionary <>が、キー値とオブジェクトを別々に指定することにより、この問題を回避する方法に注意してください。それでもオブジェクトを見つけることができない場合がありますが、少なくとも設計上失われることはありません。

于 2010-01-28T13:32:54.690 に答える
1

KeyedCollection工場出荷時の設定に伴う余分なオーバーヘッドがそれだけの価値がない場合は、独自のオーバーヘッドを簡単に実装できます。元のKeyedCollectioninSystem.Collections.ObjectModelは内部的にaDictionary<TKey, TItem>とaです。これは、との両方でList<TItem>操作を定義できることを意味します。たとえば、挿入、インデックスによるアクセス、挿入された順序でのコレクションのトラバース(すべてが容易になります)と同時に、キーに基づいたクイックルックアップ(辞書の助けを借りて)を行うことができます。つまり、アイテムを追加または削除するときは、余分なものを保持するための小さなメモリオーバーヘッドを除いて、基礎となる両方のコレクションで実行する必要があります(ただし、オブジェクトはそのように複製されません)。加算速度はあまり影響を受けませんが(加算はO(1))、IList<>IDictionary<>IList<>List<>List<>除去速度は少し影響を受けます。

挿入順序やインデックスによるアクセスを気にしない場合:

public class KeyedCollection<TKey, TItem> : ICollection<TItem>
{
    MemberInfo _keyInfo;
    Func<TItem, TKey> _keySelector;
    Dictionary<TKey, TItem> _dict;

    public TItem this[TKey key]
    {
        get { return _dict[key]; }
    }

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

    public bool IsReadOnly
    {
        get { return false; }
    }

    public ICollection<TKey> Keys
    {
        get { return _dict.Keys; }
    }

    private ICollection<TItem> Items
    {
        get { return _dict.Values; }
    }

    public KeyedCollection(Expression<Func<TItem, TKey>> keySelector, IEqualityComparer<TKey> comparer = null)
    {
        var keyExpression = keySelector.Body as MemberExpression;
        if (keyExpression != null)
            _keyInfo = keyExpression.Member;

        _keySelector = keySelector.Compile();
        _dict = new Dictionary<TKey, TItem>(comparer);
    }



    private TKey GetKeyForItem(TItem item)
    {
        return _keySelector(item);
    }

    public bool ContainsKey(TKey key)
    {
        return _dict.ContainsKey(key);
    }

    public bool Contains(TItem item)
    {
        return ContainsKey(GetKeyForItem(item));
    }

    public bool TryGetItem(TKey key, out TItem item)
    {
        return _dict.TryGetValue(key, out item);
    }

    public void Add(TItem item)
    {
        _dict.Add(GetKeyForItem(item), item);
    }

    public void AddOrUpdate(TItem item)
    {
        _dict[GetKeyForItem(item)] = item;
    }

    public bool UpdateKey(TKey oldKey, TKey newKey)
    {
        TItem oldItem;
        if (_keyInfo == null || !TryGetItem(oldKey, out oldItem) || !SetItem(oldItem, newKey))   // important
            return false;

        RemoveKey(oldKey);
        Add(oldItem);
        return true;
    }

    private bool SetItem(TItem item, TKey key)
    {
        var propertyInfo = _keyInfo as PropertyInfo;
        if (propertyInfo != null)
        {
            if (!propertyInfo.CanWrite)
                return false;

            propertyInfo.SetValue(item, key, null);
            return true;
        }

        var fieldInfo = _keyInfo as FieldInfo;
        if (fieldInfo != null)
        {
            if (fieldInfo.IsInitOnly)
                return false;

            fieldInfo.SetValue(item, key);
            return true;
        }

        return false;
    }

    public bool RemoveKey(TKey key)
    {
        return _dict.Remove(key);
    }

    public bool Remove(TItem item)
    {
        return RemoveKey(GetKeyForItem(item));
    }

    public void Clear()
    {
        _dict.Clear();
    }

    public void CopyTo(TItem[] array, int arrayIndex)
    {
        Items.CopyTo(array, arrayIndex);
    }

    public IEnumerator<TItem> GetEnumerator()
    {
        return Items.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

ICollection<TItem>私はそれをより標準に準拠するように実装しました-そしてまたあなたは素晴らしいコレクション初期化構文を手に入れます!:)

使用例:

var p1 = new Person { Name = "a" };
var p2 = new Person { Name = "b" };

var people = new KeyedCollection<string, Person>(p => p.Name) { p1, p2 };
// p1 == people["a"];
// p2 == people["b"];
于 2013-03-30T00:40:33.220 に答える
0

C#の動的プロパティの投稿は、辞書の使用が一般的な選択であったことを示しているようです。他の投稿は、HashTableの使用を提案しています

辞書とハッシュテーブル

于 2010-01-28T12:56:34.903 に答える