2つの値を返す関数について考えてみます。私たちは書くことができます:
// Using out:
string MyFunction(string input, out int count)
// Using Tuple class:
Tuple<string, int> MyFunction(string input)
// Using struct:
MyStruct MyFunction(string input)
どちらがベストプラクティスであり、その理由は何ですか?
2つの値を返す関数について考えてみます。私たちは書くことができます:
// Using out:
string MyFunction(string input, out int count)
// Using Tuple class:
Tuple<string, int> MyFunction(string input)
// Using struct:
MyStruct MyFunction(string input)
どちらがベストプラクティスであり、その理由は何ですか?
それぞれに長所と短所があります。
Outパラメータは高速で安価ですが、変数を渡し、ミューテーションに依存する必要があります。LINQでoutパラメータを正しく使用することはほとんど不可能です。
タプルは収集圧力1を作成し、自己文書化されていません。「Item1」はあまり説明的ではありません。
カスタム構造体は、大きい場合はコピーに時間がかかる場合がありますが、自己文書化されており、小さい場合は効率的です。ただし、些細な使用のためにカスタム構造体全体を定義するのも面倒です。
私は、他のすべての条件が同じであるカスタム構造体ソリューションに傾倒します。さらに良いのは、1つの値のみを返す関数を作成することです。そもそもなぜ2つの値を返すのですか?
この回答が書かれてから6年後に出荷されたC#7のタプルは値型であるため、収集圧力が発生する可能性が低いことに注意してください。
1ヒープから小さなオブジェクトを割り当てるたびに、ガベージコレクターに「プレッシャー」がかかります。プレッシャーが大きいほど、収集の頻度が高くなります。一部のアプリケーションでは、生成される収集圧力の量を制御することが重要であるため、数百万のタプルを不必要に割り当てることは、それらのアプリケーションでは悪いことになる可能性があります。もちろん、パフォーマンスに関するすべての質問と同様に、問題の大きさを理解するまで、やみくもに変更を加えないでください。
前の回答に加えて、C#7は、参照型とは異なり、値型タプルをもたらし、System.Tuple
セマンティクスも改善されています。
名前を付けずにそのままにして、.Item*
構文を使用することもできます。
(string, string, int) getPerson()
{
return ("John", "Doe", 42);
}
var person = getPerson();
person.Item1; //John
person.Item2; //Doe
person.Item3; //42
しかし、この新機能で本当に強力なのは、タプルに名前を付ける機能です。したがって、上記を次のように書き直すことができます。
(string FirstName, string LastName, int Age) getPerson()
{
return ("John", "Doe", 42);
}
var person = getPerson();
person.FirstName; //John
person.LastName; //Doe
person.Age; //42
破壊もサポートされています:
(string firstName, string lastName, int age) = getPerson()
答えは、関数が実行していることのセマンティクスと、2つの値の関係に依存すると思います。
たとえば、TryParse
メソッドは、解析された値を受け入れるためのパラメーターを受け取り、解析が成功したかどうかを示すためにout
aを返します。bool
2つの値は実際には一緒に属していないため、意味的には意味があり、out
パラメーターを使用することでコードの意図が読みやすくなります。
ただし、関数が画面上のオブジェクトのX / Y座標を返す場合、2つの値は意味的に一緒に属しているため、を使用することをお勧めしますstruct
。
tuple
メンバーを取得するための厄介な構文のため、外部コードに表示されるものには個人的にforを使用しないようにします。
Outパラメーターを使用するアプローチを使用します。これは、2番目のアプローチでは、Tupleクラスのオブジェクトを作成してから値を追加する必要があるためです。これは、outパラメーターの値を返す場合に比べてコストのかかる操作だと思います。タプルクラスで複数の値を返したい場合(実際には、1つのoutパラメーターを返すだけでは達成できません)、2番目のアプローチに進みます。
構造体の代わりにカスタムクラスを持つというもう1つのオプションについては言及していません。データに関数で操作できるセマンティクスが関連付けられている場合、またはインスタンスサイズが十分に大きい場合(経験則として> 16バイト)、カスタムクラスが推奨される場合があります。「out」の使用は、ポインターに関連付けられており、参照型がどのように機能するかを理解する必要があるため、パブリックAPIでは推奨されません。
https://msdn.microsoft.com/en-us/library/ms182131.aspx
タプルは内部使用には適していますが、パブリックAPIでは使用が厄介です。したがって、私の投票は、パブリックAPIの構造体とクラスの間です。
「ベストプラクティス」はありません。それはあなたが快適であり、あなたの状況で最もよく機能するものです。これに一貫している限り、投稿したソリューションのいずれにも問題はありません。