Paramsキーワードとリストをc#関数への入力として使用することの長所/短所は何ですか?
主に、パフォーマンスの考慮事項とその他のトレードオフは何ですか。
Paramsキーワードは、C#コンパイラによって処理されるシンタックスシュガーです。ボンネットの下で、それは実際に回っています
void Foo(params object[] a) { ... }
Foo(1,2,"THREE");
に
void Foo(object[] a) { ... }
Foo(new object[] { 1, 2, "THREE" })
performanceの観点から、あなたが質問しているように、params呼び出しは、List <>を作成するよりも配列を作成する方が少し速いため、単純に高速です。上記の2つのスニペットの間にパフォーマンスの違いはありません。
個人的には、別のプログラマーによって提供された多数の入力を受け取る関数を作成するときにparams
を使用します(たとえば、String.Format
)、およびコンピューターによって提供されるデータ項目のリストを取得する関数を作成する場合はIEnumerable
(たとえば、File.Write
)。
パフォーマンスへの影響はごくわずかです。このような些細なことのパフォーマンスについて心配しているのは、ドナルド・クヌースが有名な「時期尚早の最適化はすべての悪の根源である」という引用で正確に話していたことです。 。
とは言うものの、アスカーはそれに固執しているようですので、ここに行きます:
1000万回の反復の結果:
params took 308 ms
list took 879 ms
これらの結果から、params配列の速度が2倍強であることがわかります。これらのいずれかを1秒以内に呼び出すことができるという単純な事実1000万回は、それを心配することによって完全に時間を無駄にしていることを意味します。コードに最適なものを使用してください。
それをテストするためのコード(VS2008を使用してコンパイルおよびリリースモードで実行)
class Program
{
const int COUNT = 10000000;
static IEnumerable<string> m_value = null;
static void ParamsMethod(params string[] args)
{ m_value = args; } // do something with it to stop the compiler just optimizing this method away
static void ListMethod(List<string> args)
{ m_value = args; } // do SOMETHING with it to stop the compiler just optimizing this method away
static void Main(string[] args)
{
var s = new Stopwatch();
s.Start();
for (int i = 0; i < COUNT; ++i)
ParamsMethod("a", "b", "c");
Console.WriteLine("params took {0} ms", s.ElapsedMilliseconds);
s.Reset();
s.Start();
for (int i = 0; i < COUNT; ++i)
ListMethod(new List<string> { "a", "b", "c" });
Console.WriteLine("list took {0} ms", s.ElapsedMilliseconds);
}
}
Paramsキーワードを使用すると、次のようなコンパイラエラーを心配することなく、可変数の引数を関数に動的に渡すことができます。
public string PrefixFormatString(string p, string s, params object[] par)
{
return p + string.Format(s, par);
}
...
PrefixFormatString("COM", "Output Error #{0} - Error = {1}", errNum, errStr);
リストを渡す場合は、渡す前にリストを作成する必要があります。
public string PrefixFormatString(string p, string s, List<object> par)
{
return p + string.Format(s, par.ToArray());
}
...
List<object> l = new List<object>(new object[] { errNum, errStr });
PrefixFormatString("COM", "Output Error #{0} - Error = {1}", l);
また、関数が期待しているデータの種類の意味を隠す傾向があります。
これは、単純な配列変数を渡すのと非常に似ていることに注意してください。唯一の違いは、コンパイラがパラメータを配列に修正することです... 100%確信はありませんが、技術的な違いは単なる構文上の糖衣だと思います-どちらの場合でも、実際には何でも配列を渡しますパラメータを入力します。
params
を呼び出すと、より適切な構文が可能になりますが、異なるクラスがインターフェイスを実装する可能性があるため、リスト(_IList<>
_を意味すると仮定)はより柔軟です。 _List<>
_を渡すことは、インターフェイスでサポートされていない特定の操作(ToArray()
など)をリストで実行する必要がある場合にのみ意味があります。
さて、paramsキーワードを使用すると、次のようなメソッドに引数を入力できます。
MethodName(1, 2, 3, 4);
しかし、リストを使用すると、次のようになります。
MethodName(new List<int> {1, 2, 3, 4});
前者の方が後者よりも構文が少し明確になります。これは、渡すパラメーターが1つしかない場合に役立ちます。
// params
MethodName(1);
// List
MethodName(new List<int> {1});
params
は、可変数のパラメーターを受け取る関数の言語構造です。これは、C elipses指定子に似ています-つまり、printf(char* fmt, ...)
です。この言語はこの種の操作をサポートしており、特にコードが読みやすくなる場合は、この操作を使用することもできます。
個人的には、パラメータをスキップします。一度か二度噛まれました。どうやって?説明させてください。
このシグネチャを使用してパブリックメソッドを記述します。
public static void LogInUser(string username, string password, params string[] options)
あなたはそれをテストし、それは機能し、それは完了しました...そして別のアセンブリ/アプリケーションがあなたの関数を呼び出しています。
ここで、1か月後、署名を変更してユーザーロールを追加します。
public static void LogInUser(string username, string password, string role, params string[] options)
ああ、あなたのメソッドを呼び出すものはどう変わったか。
LogInUser("[email protected]", "zz", "Admin", "rememberMe", "800x600");
私が見ることができる2つの主な違いは、メソッドに渡されるパラメーターの数がparams
を使用してコンパイル時に設定されるのに対し、List<T>
では実行時に渡されるリストに依存することです。 。
コンパイル時にメソッドを呼び出さなければならない引数の数を修正することが賛否両論であるかどうかは、設計とその意図に完全に依存します。達成したいことによっては、どちらもメリットになる可能性があります。
Params
は読みやすさの面で役立ち、C#で取得するオプションのパラメーターに非常に近いものです。いずれかの時点で不明な数のパラメーターを消費する必要がある場合にのみ、List<T>
実装を個人的に使用します。
編集:パフォーマンスの問題に関する編集を見つけました。そのトピックについてはわかりませんが、List<T>
を使用して多数の「パラメータ」を期待できる可能性があるのに対し、params
には、コーディングする必要があるため、正気度の上限があります。
programmerメソッドの呼び出しのパフォーマンスは、paramsキーワードを使用することで改善できる場合があります。
(プログラマーはコンピューターよりもはるかにコストがかかるのに、なぜ他の種類のパフォーマンスを考えているのですか。)