web-dev-qa-db-ja.com

vs vs typeof

これらのコードのどれがより高速ですか?

if (obj is ClassA) {}

if (obj.GetType() == typeof(ClassA)) {}

編集:私は彼らが同じことをしないことを知っています。

140
ilitirit

これがその質問に答え、次にいくつかに答えるはずです。

2行目のif (obj.GetType() == typeof(ClassA)) {}は、記事を読みたくない人にとっては高速です。

160
MagicKat

彼らが同じことをしないなら、どちらが速いかは重要ですか?異なる意味を持つステートメントのパフォーマンスを比較することは、悪い考えのようです。

isは、オブジェクトがそのタイプ階層のどこかにClassAを実装しているかどうかを示します。 GetType()は、最も派生したタイプについて説明します。

同じことではありません。

185
Jay Bazuzi

彼らは同じことをしません。 objがClassA型またはClassAのサブクラスの場合、最初のものが機能します。 2番目は、ClassAタイプのオブジェクトのみに一致します。 2番目の方法は、クラス階層を確認する必要がないため、高速になります。

理由を知りたいが、 is vs typeof で参照されている記事を読みたくない人のために。

25
tvanfosson

私は彼らが同じことを行ういくつかのベンチマークを行いました-封印されたタイプ。

var c1 = "";
var c2 = typeof(string);
object oc1 = c1;
object oc2 = c2;

var s1 = 0;
var s2 = '.';
object os1 = s1;
object os2 = s2;

bool b = false;

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
    b = c1.GetType() == typeof(string); // ~60ms
    b = c1 is string; // ~60ms

    b = c2.GetType() == typeof(string); // ~60ms
    b = c2 is string; // ~50ms

    b = oc1.GetType() == typeof(string); // ~60ms
    b = oc1 is string; // ~68ms

    b = oc2.GetType() == typeof(string); // ~60ms
    b = oc2 is string; // ~64ms


    b = s1.GetType() == typeof(int); // ~130ms
    b = s1 is int; // ~50ms

    b = s2.GetType() == typeof(int); // ~140ms
    b = s2 is int; // ~50ms

    b = os1.GetType() == typeof(int); // ~60ms
    b = os1 is int; // ~74ms

    b = os2.GetType() == typeof(int); // ~60ms
    b = os2 is int; // ~68ms


    b = GetType1<string, string>(c1); // ~178ms
    b = GetType2<string, string>(c1); // ~94ms
    b = Is<string, string>(c1); // ~70ms

    b = GetType1<string, Type>(c2); // ~178ms
    b = GetType2<string, Type>(c2); // ~96ms
    b = Is<string, Type>(c2); // ~65ms

    b = GetType1<string, object>(oc1); // ~190ms
    b = Is<string, object>(oc1); // ~69ms

    b = GetType1<string, object>(oc2); // ~180ms
    b = Is<string, object>(oc2); // ~64ms


    b = GetType1<int, int>(s1); // ~230ms
    b = GetType2<int, int>(s1); // ~75ms
    b = Is<int, int>(s1); // ~136ms

    b = GetType1<int, char>(s2); // ~238ms
    b = GetType2<int, char>(s2); // ~69ms
    b = Is<int, char>(s2); // ~142ms

    b = GetType1<int, object>(os1); // ~178ms
    b = Is<int, object>(os1); // ~69ms

    b = GetType1<int, object>(os2); // ~178ms
    b = Is<int, object>(os2); // ~69ms
}

sw.Stop();
MessageBox.Show(sw.Elapsed.TotalMilliseconds.ToString());

ジェネリック型をテストするジェネリック関数:

static bool GetType1<S, T>(T t)
{
    return t.GetType() == typeof(S);
}
static bool GetType2<S, T>(T t)
{
    return typeof(T) == typeof(S);
}
static bool Is<S, T>(T t)
{
    return t is S;
}

カスタムタイプも試してみましたが、結果は一貫していました。

var c1 = new Class1();
var c2 = new Class2();
object oc1 = c1;
object oc2 = c2;

var s1 = new Struct1();
var s2 = new Struct2();
object os1 = s1;
object os2 = s2;

bool b = false;

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < 10000000; i++)
{
    b = c1.GetType() == typeof(Class1); // ~60ms
    b = c1 is Class1; // ~60ms

    b = c2.GetType() == typeof(Class1); // ~60ms
    b = c2 is Class1; // ~55ms

    b = oc1.GetType() == typeof(Class1); // ~60ms
    b = oc1 is Class1; // ~68ms

    b = oc2.GetType() == typeof(Class1); // ~60ms
    b = oc2 is Class1; // ~68ms


    b = s1.GetType() == typeof(Struct1); // ~150ms
    b = s1 is Struct1; // ~50ms

    b = s2.GetType() == typeof(Struct1); // ~150ms
    b = s2 is Struct1; // ~50ms

    b = os1.GetType() == typeof(Struct1); // ~60ms
    b = os1 is Struct1; // ~64ms

    b = os2.GetType() == typeof(Struct1); // ~60ms
    b = os2 is Struct1; // ~64ms


    b = GetType1<Class1, Class1>(c1); // ~178ms
    b = GetType2<Class1, Class1>(c1); // ~98ms
    b = Is<Class1, Class1>(c1); // ~78ms

    b = GetType1<Class1, Class2>(c2); // ~178ms
    b = GetType2<Class1, Class2>(c2); // ~96ms
    b = Is<Class1, Class2>(c2); // ~69ms

    b = GetType1<Class1, object>(oc1); // ~178ms
    b = Is<Class1, object>(oc1); // ~69ms

    b = GetType1<Class1, object>(oc2); // ~178ms
    b = Is<Class1, object>(oc2); // ~69ms


    b = GetType1<Struct1, Struct1>(s1); // ~272ms
    b = GetType2<Struct1, Struct1>(s1); // ~140ms
    b = Is<Struct1, Struct1>(s1); // ~163ms

    b = GetType1<Struct1, Struct2>(s2); // ~272ms
    b = GetType2<Struct1, Struct2>(s2); // ~140ms
    b = Is<Struct1, Struct2>(s2); // ~163ms

    b = GetType1<Struct1, object>(os1); // ~178ms
    b = Is<Struct1, object>(os1); // ~64ms

    b = GetType1<Struct1, object>(os2); // ~178ms
    b = Is<Struct1, object>(os2); // ~64ms
}

sw.Stop();
MessageBox.Show(sw.Elapsed.TotalMilliseconds.ToString());

そしてタイプ:

sealed class Class1 { }
sealed class Class2 { }
struct Struct1 { }
struct Struct2 { }

推論:

  1. GetTypesでstructを呼び出すのが遅い。GetTypeは、サブタイプでオーバーライドできないobjectクラスで定義されているため、structsは、GetTypeと呼ばれるようにボックス化する必要があります。

  2. オブジェクトインスタンスでは、GetTypeは高速ですが、非常にわずかです。

  3. ジェネリック型では、Tclassの場合、isははるかに高速です。_Tstructの場合、isGetTypeよりもはるかに高速ですが、typeof(T)は両方よりもはるかに高速です。Tclassである場合、typeof(T)は異なるため信頼性がありません実際の基礎となるタイプt.GetTypeから。

つまり、objectインスタンスがある場合は、GetTypeを使用します。汎用のclassタイプがある場合は、isを使用します。汎用のstructタイプがある場合は、typeof(T)を使用します。ジェネリック型が参照型か値型かわからない場合は、isを使用します。常に1つのスタイルと一貫性を保ちたい場合(シールタイプの場合)、is。を使用します。

16
nawfal