たまたま、コード設計に関する1つの質問があります。たとえば、「変更」する可能性のあるいくつかの関数を呼び出す「テンプレート」メソッドが1つあります。直感的なデザインは、「テンプレートデザインパターン」に従うことです。変更関数を、サブクラスでオーバーライドされる「仮想」関数として定義します。または、「仮想」なしでデリゲート関数を使用することもできます。デリゲート関数は、カスタマイズできるように挿入されています。
もともと、2番目の「デリゲート」方法は「仮想」方法よりも高速だと思っていましたが、一部のコーディングスニペットはそれが正しくないことを証明しています。
以下のコードでは、最初のDoSomethingメソッドは「テンプレートパターン」に従います。仮想メソッドIsTokenCharを呼び出します。2番目のDoSomthingメソッドは、仮想関数に依存しません。代わりに、パスインデリゲートがあります。私のコンピューターでは、最初のDoSomthingは常に2番目のDoSomthingよりも高速です。結果は1645:1780のようになります。
「仮想呼び出し」は動的バインディングであり、直接委任呼び出しよりも時間のかかる作業ですよね?しかし、結果はそうではないことを示しています。
誰でもこれを説明できますか?
using System;
using System.Diagnostics;
class Foo
{
public virtual bool IsTokenChar(string word)
{
return String.IsNullOrEmpty(word);
}
// this is a template method
public int DoSomething(string word)
{
int trueCount = 0;
for (int i = 0; i < repeat; ++i)
{
if (IsTokenChar(word))
{
++trueCount;
}
}
return trueCount;
}
public int DoSomething(Predicate<string> predicator, string word)
{
int trueCount = 0;
for (int i = 0; i < repeat; ++i)
{
if (predicator(word))
{
++trueCount;
}
}
return trueCount;
}
private int repeat = 200000000;
}
class Program
{
static void Main(string[] args)
{
Foo f = new Foo();
{
Stopwatch sw = Stopwatch.StartNew();
f.DoSomething(null);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
{
Stopwatch sw = Stopwatch.StartNew();
f.DoSomething(str => String.IsNullOrEmpty(str), null);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
}
}