2017-10-13 9 views
3

のは、私は文字列プロパティ辞書にキーとして文字列プロパティを追加すると、文字列が複製されますか?適切な回避策はありますか?

public class Something 
{ 
    public int SomeIntProperty { get; set; } 
    public string SomeStringProperty { get; set; } 
} 

を持つクラスを持っているとしましょうとのはSomeStringProperty sが非常に長くなることができると私は私がのためにメモリに保持する辞書

this.dic = somethings 
    .GroupBy(s => s.SomeStringProperty) 
    .ToDictionary(g => g.Key); 

を作成したいとしましょうアプリケーションが実行されている時間。私の質問は、文字列が値型のように動作するため、辞書に保持される文字列の複製が終了するかどうかです。もしそうなら、私は代わりに文字列への参照を保持するか、/ hash/etcを圧縮するための回避策は何ですか。それら?

答えて

3

私の質問は、文字列が値型のように動作するため、辞書に保持される文字列の複製が終了するかどうかです。

C#の文字列は値型ではありません。これらの文字列は、ほとんど同じように動作しません。

C#文字列は不変であり、連想型コンテナのキーとしての使用に適しています。ただし、文字列をキーとして使用したり、その他の容量で使用したりしても、コンテンツは複製されません。

ソース配列のSomeStringPropertyまでの辞書キーの参照の等価性をチェックすることで、クローニングが行われていないことを確認できます。辞書の各キーは、ソース・アレイ中に存在するであろう:による文字列は値型のように振る舞うように

var data = new[] { 
    new Something {SomeIntProperty=1, SomeStringProperty="A"} 
, new Something {SomeIntProperty=2, SomeStringProperty="A"} 
, new Something {SomeIntProperty=3, SomeStringProperty="A"} 
, new Something {SomeIntProperty=4, SomeStringProperty="A"} 
, new Something {SomeIntProperty=5, SomeStringProperty="A"} 
, new Something {SomeIntProperty=6, SomeStringProperty="B"} 
, new Something {SomeIntProperty=7, SomeStringProperty="B"} 
, new Something {SomeIntProperty=8, SomeStringProperty="C"} 
, new Something {SomeIntProperty=9, SomeStringProperty="D"} 
}; 
var dict = data.GroupBy(s => s.SomeStringProperty) 
        .ToDictionary(g => g.Key); 
foreach (var key in dict.Keys) { 
    if (data.Any(s => ReferenceEquals(s.SomeStringProperty, key))) { 
     Console.WriteLine("Key '{0}' is present.", key); 
    } else { 
     Console.WriteLine("Key '{0}' is not present.", key); 
    } 
} 

上記コード印刷

Key 'A' is present. 
Key 'B' is present. 
Key 'C' is present. 
Key 'D' is present. 

Demo.

1

文字列は値型ではなく、不変です参照型。辞書

間違って保持するための文字列を複製することになります

、あなたはあなたがそれらを変更しようとすると新しい文字列を作成することになります。新しいコンテンツを含む新しい文字列が作成されます。

1

ドキュメントには、文字列が不変ですが、我々はそれを変更するまで、実行時には元の値への参照を保持し、ので、この場合には誤解を招くされString変数値によってを、渡して説明します。

そこで、LINQのToDictionary()方法は、Dictionary.Add()under the hoodの両方SomeStringPropertyおよびメモリ内の同じ場所にDictonaryキーポイントを引数として文字列を渡していても。しかし

、我々はキーセレクタで文字列を変更した場合:

.ToDictionary(g => g.Key + "changed!"); 

...その後、ランタイムは新しいキーを作成するには、元の文字列値をコピーします。

我々は、基準が同じであることを確認することができる:

var first = this.dict.First(); 
Console.WriteLine(object.ReferenceEquals(first.Key, first.Value.SomeStringProperty)); 

This articleはC#でStringオブジェクトのニュアンスを説明する素晴らしい仕事をしていません。

+0

偉大な簡潔な説明。参照:[この回答](https://stackoverflow.com/questions/10792603/how-are-strings-passed-in-net) –

関連する問題