SteringJoinerは、パフォーマンスの低下した文字列のスペルコードを救います.

10284 ワード

回転:
http://www.cnblogs.com/coolcode/archive/2009/10/13/StringJoiner.html
前言
一般プログラマが持っている最も「強い」二つの武器はコピーと貼り付けです.
 
String
この文章は皆さんのテクニックを紹介したいです.
私たちは知っています.または、一日目にCハを勉強する時にstringのタイプを知っています.そして、一番簡単なつづり合わせのstringの書き方はすぐ分かります.
string s = string.Empty;

s += "Bruce";

s += "Who?";

s += "a guy think sth different...";
 
このような書き方は本当に簡単で素晴らしいです.C言語のstracat書き方に比べて、C書を使うのは本当に幸せです.またいつまでこのような書き方を支持するか分かりません.
s += "Bruce" + " Lee";
(いつから上記の書き方を支持するか分かりません.覚えています.Net 2.0はこのように書いてはいけません.Net 1.1は絶対だめです.必ず括弧を入れます.
s += ("Bruce" + " Lee");
)
StringBuider
しかし、この幸福感は初心者にはStringBuiderの存在を知らないかもしれません.たまに他の人の文章でStringBuiderを見ても、なぜ「+=」があるのか分かりません.
StringBuilder sb = new StringBuilder();

sb.Append("Bruce");

sb.Append("Who?");

sb.Append("a guy think sth different...");
 
信じられないかもしれませんが、企業で仕事をしているつもりです.Netで一年か二年働いている友達はまだStringBuiderの存在を知らない人がいます.特にAsp.Netの中では、多くの友達がCのプラカードを使ってフロントコードの山を作っています.Html文やJavaScript、さらにSQL文など、例外なく「+=」を使ってつづり合わせています.お尻をたたくと人が逃げてしまいます.何十行も残しています.
我々は、最初の方法を使って文字列をつなぎ合わせても、時間や空間の性能からしても、StringBuiderを使うよりは遠いことを知っているはずです.
いい子はここを見ると、早く帰って自分のあの「+=」を全部StringBuiderのアプリに変えてしまうかもしれません.とりあえず焦らないでください.方式から二転换するのはとても时间がかかります.绝対に苦しいです.今はどうやって一番速い方法で一つのコード性能を方式の二にアップするかを教えます.
 
Stering Joiner
簡単です.string sをString Joiner sに変えたら大成功です.すなわち
StringJoiner s = string.Empty;

s += "Bruce";

s += "Who?";

s += "a guy think sth different...";
 
なぜこんなに簡単に性能が上がるのですか?私をだましますか
もちろんみんなをだましているのではありませんて、マジックをするのではありませんて、文章の最後に性能のテストデータがあって、真相があります.
今は私にStringJoinerのベールを開けさせてください.最後にきっと言います.
StringJoinerは装飾者モードのようです.外にはStringBuiderが隠れています.魔術師が道具を一山袖に隠して観客を騙すのが好きです.
public class StringJoiner 

{

    protected StringBuilder Builder;



    public StringJoiner()

    {

        Builder = new StringBuilder();

    }

}
(Buiderをprotectedと定義し、いつかStering Joinerを引き継いで「観客をゆらす」ことが必要かもしれないと期待する)
StringJoinerはどうやって先ほどのコードを実現しますか?
1.暗黙的な変換
例えば:
StringJoiner s = string.Empty;
 
の答えは:
public static implicit operator StringJoiner(string value)

{

    StringJoiner text = new StringJoiner();

    text.Builder.Append(value);

    return text;

}
(新規オブジェクトを作成して、SteringBuilderのApppendメソッドに値を移す)
 
2.操作子をリロードする
例えば:
s += "Bruce";
 
の答えは:
public static StringJoiner operator +(StringJoiner self, string value)

{

    self.Builder.Append(value);

    return self;

}
(StringJoinerとstringタイプを実現するには、演算子「+」で操作できます.同様に、StringBuiderに文字列を渡すApppend方法です.)
より一般的にするために、他のタイプとの接続が実現される場合:
s += 123;

s += 0.314;

s += 'c';
 
したがって、Stering Joiner+Objectを積載しなければなりません.
public static StringJoiner operator +(StringJoiner self, object value)

{

    self.Builder.Append(value);

    return self;

}
 
最後に、StringJoinerの「ゆらゆら」レベルをさらに上にするためには、String Joinerのオブジェクトは、stringタイプに暗黙的に変換することができる必要がある.
public static implicit operator string(StringJoiner value)

{

    return value.ToString();

}



public override string ToString()

{

    return this.Builder.ToString();

}
 
もちろん、この時点でStringJoinerは十分です.もっと徹底的な「ゆらゆら」は本文の目的ではありません.StringJoinerはstringの代わりをしたいのではなく、StringBuiderの代わりをしたいのではなく、むしろ私はSteringBuiderを使うことに賛成しています.しかし、「string+=」によってもたらされる悲惨なコードを再構築したいなら、Stering Joinerを使いましょう.
 
性能テスト
性能カウンタ:CodeTimer(XP版)
テストコード(3つの異なる方法で1万回の文字列を綴じ合わせ、1万回の整数を綴じ合わせ、10回以上の操作を繰り返す):
static void Main(string[] args)

{

    CodeTimer.Time("", 1, () => { });



    //   +=      

    CodeTimer.Time("NormalString", 10, () => NormalString());



    //StringJoiner      

    CodeTimer.Time("StringJoiner", 10, () => StringJoiner());



    //StringBuilder      

    CodeTimer.Time("StringBuilder", 10, () => StringBuilder());



    Console.WriteLine("continue...");

    Console.Read();

}



//       

const int stringLength = 10000;



static void NormalString()

{

    string s = string.Empty;

    for (int i = 0; i < stringLength; i++)

        s += "A";//     

    s = string.Empty;

    for (int i = 0; i < stringLength; i++)

        s += 1;//    

    string result = s;

}



static void StringJoiner()

{

    StringJoiner s = string.Empty;

    for (int i = 0; i < stringLength; i++)

        s += "A";

    s = string.Empty;

    for (int i = 0; i < stringLength; i++)

        s += 1;

    string result = s;

}



static void StringBuilder()

{

    StringBuilder s = new StringBuilder(string.Empty);

    for (int i = 0; i < stringLength; i++)

        s.Append("A");

    s = new StringBuilder(string.Empty);

    for (int i = 0; i < stringLength; i++)

        s.Append(1);

    string result = s.ToString();

}
 
一回のテスト結果:
 

NormalString

        Time Elapsed:           667ms

        Time Elapsed (one time):66ms

        CPU time:               671,875,000ns

        CPU time (one time):    67,187,500ns

        Gen 0:                  1908

        Gen 1:                  0

        Gen 2:                  0

 

StringJoiner

        Time Elapsed:           19ms

        Time Elapsed (one time):1ms

        CPU time:               15,625,000ns

        CPU time (one time):    1,562,500ns

        Gen 0:                  3

        Gen 1:                  0

        Gen 2:                  0

 

StringBuilder

        Time Elapsed:           19ms

        Time Elapsed (one time):1ms

        CPU time:               15,625,000ns

        CPU time (one time):    1,562,500ns

        Gen 0:                  3

        Gen 1:                  0

        Gen 2:                  0

 
上の図からは、StringJoinerとStringBuiderの性能はフラットであり、それらはいずれも第一の方法よりもはるかにリードしていることが分かります.