具体的な理由から、アプリケーションでは2種類のディクショナリラッパーを使用する必要があります(値型、次のようになります:"class"型と "struct"型制約の両方で動作するジェネリッククラスを設計する必要がある
internal class StructDictionary<K, V> where V : struct
{
public IDictionary<K, V> _dictionary = new Dictionary<K, V>();
public StructDictionary(Dictionary<K, V> dictionary)
{
_dictionary = dictionary;
}
public V? this[K key]
{
get
{
V foundValue;
return _dictionary.TryGetValue(key, out foundValue) ? foundValue : (V?)null;
}
set
{
if (!value.HasValue)
return;
_dictionary[key] = value.Value;
}
}
}
とインスタンスタイプ
internal class InstanceDictionary<K, V> where V : class
{
public IDictionary<K, V> _dictionary = new Dictionary<K, V>();
public InstanceDictionary(Dictionary<K, V> dictionary)
{
_dictionary = dictionary;
}
public V this[K key]
{
get
{
V foundValue;
return _dictionary.TryGetValue(key, out foundValue) ? foundValue : null;
}
set
{
if (value == null)
return;
_dictionary[key] = value;
}
}
}
のためにこれらの2クラスは、次のように使用されることを意図されています
void Main()
{
var structDictionary = new StructDictionary<string, double>(new Dictionary<string, double>(){{"key1",1}});
var instanceDictionary = new InstanceDictionary<string, string>(new Dictionary<string, string>(){{"key1","value1"}});
structDictionary["key1"] = 70;
instanceDictionary["key1"] = "NEW_VAL";
}
を
2つの辞書ラッパーのロジックは事実上同じなので、2つのクラスを1つのクラスに置き換えて、には影響しません。これらのオブジェクトは広範囲に使用されるためパフォーマンスに影響します。
これまで、私は基本的にインデクサーからオブジェクトを返すこの最適ではない解決策を見つけました。この解決策はボクシング/アンボクシング(下のコードのコメントを参照)があり、非常に高速ではないConvert.ChangeTypeも使用しているので実際には機能しません。
internal class BetterDictionary<K, V>
{
public IDictionary<K, V> _dictionary = new Dictionary<K, V>();
public BetterDictionary(Dictionary<K, V> dictionary)
{
_dictionary = dictionary;
}
public object this[K key]
{
get
{
V foundValue;
return _dictionary.TryGetValue(key, out foundValue) ? (object)foundValue /* Issue 1: boxing here when V is value type */: null;
}
set
{
if (value==null)
return;
_dictionary[key] = (V)Convert.ChangeType(value, typeof(V)); // Issue 2: slight performance hit due to ChangeType ?
// more code here
}
}
}
結論として、パフォーマンスに影響を与えないよりよい解決策(より良いBetterDictionaryラッパー)があり、基本的に私はVジェネリックパラメータの値の型とインスタンスタイプの両方をサポートする汎用オブジェクトをしたいです。私は私が唯一のものでインデクサーを持つオブジェクトにバインドすることができ、いくつかの特定の癖を持っている従来のUIライブラリで働いているので、それはだ、このやや特異な辞書ラッパーを使用する必要がない理由質問に対して
EDITフォーム、追加私は存在しない辞書の値のnullを返す必要があります。基本的には、UIのグリッド列として表示するための辞書データを移調しています。UIを変更することはできませんし、内部の辞書を変更することもできないため、このようなラッパーを使用しなければなりませんでした。
また、インデクサーセット{}は実際には辞書値を設定するだけでなく、辞書を使用できないため、より多くのコードを実行しています。
文脈の欠如に対する謝罪、私はより多くの文脈で例を更新しようとします。
私は混乱していると思います。なぜインデクサーを 'public V this [K key]'にして変換をスキップできないのですか? –
ラッピングの目的の1つである、そのキーの値がない場合は、nullを返す必要があります。 – brakeroo
だから、基本的には 'TryGetValue()'が失敗した場合に 'null'を返そうとするラッパーとして使うだけです。個人的には、単純な古い辞書と 'TryGetValue'を直接使用することをお勧めします。あなたが本当にあなたの 'BetterDictionary'を動作させたいなら、私が持っている最良のアイデアは、私が言及したようにインデクサーから' V'を返すことです。次に、nullの代わりに 'default(V)'を使用するように、見つからないケースを変更します。次に、ヌル可能型を 'V'として明示的に定義した場合、あなたは望みどおりにnullを取得し、制約のない本当に汎用クラスを持ちます。 –