params キーワードと List を c# 関数への入力として使用することの長所と短所は何ですか?
主に、パフォーマンスに関する考慮事項とその他のトレードオフは何ですか。
params キーワードと List を c# 関数への入力として使用することの長所と短所は何ですか?
主に、パフォーマンスに関する考慮事項とその他のトレードオフは何ですか。
params キーワードは、C# コンパイラによって処理されるシンタックス シュガーです。ボンネットの下で、実際に回転しています
void Foo(params object[] a) { ... }
Foo(1,2,"THREE");
の中へ
void Foo(object[] a) { ... }
Foo(new object[] { 1, 2, "THREE" })
あなたが求めているようなパフォーマンスの観点からは、List<>を作成するよりも配列を作成する方が少し速いため、params呼び出しは単に高速です。上記の 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キーワードを使用すると、次のようなメソッドに引数を入力できます。
MethodName(1, 2, 3, 4);
しかし、リストを使用すると、次のようになります。
MethodName(new List<int> {1, 2, 3, 4});
前者の方が後者よりも構文が少し明確になる可能性があります。これは、渡すパラメータが1つしかない場合に便利です。
// params
MethodName(1);
// List
MethodName(new List<int> {1});
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
は、可変数のパラメーターを受け取る関数の言語構造です。これは、C楕円指定子に似ています-つまり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("z@z.com", "zz", "Admin", "rememberMe", "800x600");
私が見ることができる2つの主な違いは、メソッドに渡されるパラメーターの数は、コンパイル時にを使用して設定されるのparams
に対し、List<T>
それは実行時に渡されるリストに依存することです。
コンパイル時にメソッドを呼び出さなければならない引数の数を修正することが賛否両論であるかどうかは、設計とその意図に完全に依存します。達成したいことによっては、どちらもメリットになる可能性があります。
Params
読みやすさの面で役立ち、C#で取得するオプションのパラメーターに非常に近いです。List<T>
いずれかの時点で不明な数のパラメーターを消費する必要がある場合にのみ、実装を個人的に使用します。
編集:パフォーマンスの問題に関する編集を見つけました。そのトピックについてはわかりませんが、を使用して多数の「パラメータ」を期待できる可能性がある場合は、コーディングする必要があるため、正気度の上限がありますList<T>
。params
メソッドを呼び出すプログラマーのパフォーマンスは、params キーワードを使用することで改善される場合があります。
(プログラマーのコストがコンピューターよりもはるかに高いことを考えると、なぜ他の種類のパフォーマンスを考えているのですか。)