型の判別その2
ジェネリックもちょっと交えて調べてみる。
Static 200 181 178 Generic 393 358 379 IsInstanceOf 628 582 633 Equal 254 239 258 GenericEqual 256 238 256
昨日言ったことと矛盾するけどただのis演算子が一番速い。オブジェクトの構成を簡単にしたためだろうか。
対して、is Tの形だとだいぶ遅くなる。ジェネリック型に対するisは多少遅くなる。
Typeの==は安定している。Genericに対するものも結果は変わらない。しかしループの中で毎回typeof(T)をするようにすると格段に遅くなる。
GenericEqual(typeof(T)) 406 379 407
といっても1000万回やって0.4秒ぐらいなのでどうということもないだろう。
IsInstanceOfも結構速い。継承階層の構成次第で早くも遅くもなるようだ。
結局isと==はどっちが速いのか。昨日のやつを継承階層を単純に、Parentから直接Child12個を派生させる形にして調べてみた。
IsTest 134 EqualTest 103
まだ==が速い。多分何回もifをやるときに、==だと一度GetType()して取得したTypeを使いまわせるけど、if(item is Type)の形だと暗黙にitem.GetType()を毎回しなきゃならなくなる、といった違いなんじゃなかろうか。わからん。
ソースと結果
using System; using System.Collections.Generic; using System.Linq; using System.Windows.Forms; using System.Diagnostics; namespace Test { class R { public int Yes; public int No; } class Parent { } class Child1 : Parent { } class Child2 : Parent { } class Program { Parent[] Generate() { var rand = new Random(); var module = typeof(Parent).Module; return Enumerable.Range(0, 10000000) .Select(i =>{ if (rand.Next(2) == 0) { return (Parent)new Child1(); } else { return (Parent)new Child2(); } }).ToArray(); } R Static(Parent[] parents) { int yes = 0, no = 0; for (int i = 0; i < parents.Length; ++i) { if (parents[i] is Child1) { ++yes; } else { ++no; } } return new R { Yes = yes, No = no }; } R IsInstanceOf(Parent[] parents) { int yes = 0, no = 0; for (int i = 0; i < parents.Length; ++i) { if (typeof(Child1).IsInstanceOfType(parents[i])) { ++yes; } else { ++no; } } return new R { Yes = yes, No = no }; } R Generic<T>(Parent[] parents) { int yes = 0, no = 0; for (int i = 0; i < parents.Length; ++i) { if (parents[i] is T) { ++yes; } else { ++no; } } return new R { Yes = yes, No = no }; } R Equal(Parent[] parents) { int yes = 0, no = 0; Type t = typeof(Child1); for (int i = 0; i < parents.Length; ++i) { if (parents[i].GetType() == t) { ++yes; } else { ++no; } } return new R { Yes = yes, No = no }; } R GenericEqual<T>(Parent[] parents) { int yes = 0, no = 0; Type t = typeof(T); for (int i = 0; i < parents.Length; ++i) { if (parents[i].GetType() == t) { ++yes; } else { ++no; } } return new R { Yes = yes, No = no }; } void Do(Parent[] parents) { Stopwatch sw = new Stopwatch(); sw.Start(); var s = Static(parents); sw.Stop(); Console.WriteLine("Static " + Tick(sw)); sw.Reset(); sw.Start(); var g = Generic<Child1>(parents); sw.Stop(); Console.WriteLine("Generic " + Tick(sw)); sw.Reset(); sw.Start(); var a = IsInstanceOf(parents); sw.Stop(); Console.WriteLine("IsInstanceOf " + Tick(sw)); sw.Reset(); sw.Start(); var e = Equal(parents); sw.Stop(); Console.WriteLine("Equal " + Tick(sw)); sw.Reset(); sw.Start(); var ge = GenericEqual<Child1>(parents); sw.Stop(); Console.WriteLine("GenericEqual " + Tick(sw)); } long Tick(Stopwatch sw) { return sw.ElapsedMilliseconds; } static void Main() { var p = new Program(); var sw = new Stopwatch(); sw.Start(); var parents = p.Generate(); sw.Stop(); Console.WriteLine("Generate " + p.Tick(sw)); p.Do(parents); p.Do(parents); p.Do(parents); } } }