[解決済み] System.ValueTupleとSystem.Tupleの違いは何ですか?
質問
C# 7 のライブラリをデコンパイルしてみたところ
ValueTuple
ジェネリックが使用されています。とは何ですか?
ValueTuples
で、なぜ
Tuple
の代わりに?
- https://docs.microsoft.com/en-gb/dotnet/api/system.tuple
- https://docs.microsoft.com/en-gb/dotnet/api/system.valuetuple
解決方法は?
<ブロッククオート
何が
ValueTuples
で、なぜ
Tuple
の代わりに?
A
ValueTuple
は、タプルを反映した構造体であり、元の
System.Tuple
クラスがあります。
との主な違いは
Tuple
と
ValueTuple
があります。
-
System.ValueTuple
は値型(構造体)であるのに対しSystem.Tuple
は参照型 (class
). これは、アロケーションとGCプレッシャーについて話すときに意味があります。 -
System.ValueTuple
だけではありません。struct
であり、それは ミュータブル として使用する場合は、注意が必要です。あるクラスがSystem.ValueTuple
をフィールドとして使用します。 -
System.ValueTuple
は、プロパティではなくフィールドを介してその項目を公開します。
C# 7までは、タプルを使うのはあまり便利ではありませんでした。そのフィールド名は
Item1
,
Item2
他の多くの言語(PythonやScala)がそうであるように、言語がこれらのためのシンタックスシュガーを提供していなかったのです。
.NET言語設計チームがタプルを組み込み、言語レベルでタプルにシンタックスシュガーを追加することを決定したとき、重要な要素はパフォーマンスでした。そのため
ValueTuple
値型であるため、(実装の詳細として)スタックに割り当てられるので、使用時のGCプレッシャーを避けることができます。
さらに
struct
はランタイムによって自動的に (浅い) 等号の意味を持つようになります。
class
はない。設計チームは、タプルに対してさらに最適化された等式があることを確認し、そのためにカスタム等式を実装しました。
以下は
のデザインノートです。
Tuples
:
構造体かクラスか
前述の通り、私はタプル型の
structs
よりもclasses
そのため、割り当てのペナルティはありません。これらの は、できるだけ軽量にする必要があります。論外です。
structs
の方がコスト高になる可能性があります。 はより大きな値をコピーします。そのため、もしこれらの値が割り当てられる回数が が作成されるとstructs
は悪い選択だと思います。しかし、タプルはその動機からして、刹那的なものです。そのため 全体よりも部分が重要な場合です。だから、一般的な を構築し、返し、すぐに分解するパターンです。 である。このような状況では、明らかに構造体が望ましいと言えます。
構造体には他にも多くの利点がありますが、それは今後明らかになっていくでしょう。 で明らかになります。
例
を使えば、簡単にわかると思います。
System.Tuple
はすぐに曖昧になります。例えば、あるメソッドで
List<Int>
:
public Tuple<int, int> DoStuff(IEnumerable<int> values)
{
var sum = 0;
var count = 0;
foreach (var value in values) { sum += value; count++; }
return new Tuple(sum, count);
}
受信側では、次のようになります。
Tuple<int, int> result = DoStuff(Enumerable.Range(0, 10));
// What is Item1 and what is Item2?
// Which one is the sum and which is the count?
Console.WriteLine(result.Item1);
Console.WriteLine(result.Item2);
値のタプルを名前付き引数に分解する方法は、この機能の真価を発揮します。
public (int sum, int count) DoStuff(IEnumerable<int> values)
{
var res = (sum: 0, count: 0);
foreach (var value in values) { res.sum += value; res.count++; }
return res;
}
そして受信側。
var result = DoStuff(Enumerable.Range(0, 10));
Console.WriteLine($"Sum: {result.Sum}, Count: {result.Count}");
または
var (sum, count) = DoStuff(Enumerable.Range(0, 10));
Console.WriteLine($"Sum: {sum}, Count: {count}");
コンパイラーグッズです。
先ほどの例の裏側を見ると、コンパイラがどのように
ValueTuple
分解を依頼したとき
[return: TupleElementNames(new string[] {
"sum",
"count"
})]
public ValueTuple<int, int> DoStuff(IEnumerable<int> values)
{
ValueTuple<int, int> result;
result..ctor(0, 0);
foreach (int current in values)
{
result.Item1 += current;
result.Item2++;
}
return result;
}
public void Foo()
{
ValueTuple<int, int> expr_0E = this.DoStuff(Enumerable.Range(0, 10));
int item = expr_0E.Item1;
int arg_1A_0 = expr_0E.Item2;
}
内部的には、コンパイルされたコードは
Item1
と
Item2
しかし、分解されたタプルを扱うので、これらはすべて抽象化されています。名前付き引数を持つタプルには
TupleElementNamesAttribute
. 分解する代わりに、1つの新鮮な変数を使用すると、次のようになります。
public void Foo()
{
ValueTuple<int, int> valueTuple = this.DoStuff(Enumerable.Range(0, 10));
Console.WriteLine(string.Format("Sum: {0}, Count: {1})", valueTuple.Item1, valueTuple.Item2));
}
アプリケーションをデバッグするときに、コンパイラが (属性を使って) 何か魔法をかけなければならないことに注意してください。
Item1
,
Item2
.
関連
-
[解決済み] C#のStringとstringの違いは何ですか?
-
[解決済み] .NETでのdecimal, float, doubleの違い?
-
[解決済み] なぜList<T>を継承しないのですか?
-
[解決済み] C#のconstとreadonlyの違いは何ですか?
-
[解決済み] Static readonly」対「const」。
-
[解決済み] フィールドとプロパティの違いは何ですか?
-
[解決済み] SelectとSelectManyの違い
-
[解決済み] リストとタプルの違いは何ですか?
-
[解決済み] Pythonの「名前付きタプル」とは何ですか?
-
[解決済み] キーワード「ref」と「out」の違いは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】「未割り当てのローカル変数を使用」とはどういう意味ですか?
-
[解決済み】WebForms UnobtrusiveValidationModeは、jqueryのScriptResourceMappingを必要とする
-
[解決済み] [Entity Framework 4.1でエンティティに関連オブジェクトを追加する際に、エンティティオブジェクトをIEntityChangeTracker.の複数のインスタンスから参照できない。
-
[解決済み】ソケットのアドレス(プロトコル/ネットワークアドレス/ポート)は、通常1つしか使用できない?
-
[解決済み】トランスポート接続からデータを読み取れない:既存の接続は、リモートホストによって強制的に閉じられました。
-
[解決済み] UnityでOnCollisionEnterが呼ばれない
-
[解決済み】Entity FrameworkからのSqlException - セッション内で他のスレッドが動作しているため、新しいトランザクションは許可されません。
-
[解決済み】値をNULLにすることはできません。パラメータ名:source
-
[解決済み】ユーザー設定値を別のユーザー設定値で設定する
-
[解決済み】スレッド終了またはアプリケーションの要求により、I/O操作が中断されました。