web-dev-qa-db-ja.com

オブジェクトが値型であるかどうかを確認する最も効率的な方法

警告:このコードは吸う、ANTHONYのコメントを参照

どちらが速いですか?

1。

  public bool IsValueType<T>(T obj){
       return obj is ValueType;
  }

2。

  public bool IsValueType<T>(T obj){
       return obj == null ? false : obj.GetType().IsValueType;
  } 

3。

  public bool IsValueType<T>(T obj){
       return default(T) != null;
  }

4.その他

41
smartcaveman

オブジェクトを実際にテストするのではなく、typeをテストする必要があります。それらを呼び出すには、発信者はタイプを知っている必要がありますが...署名<T>(T obj)が与えられた場合、唯一の正解は次のとおりです。

_public bool IsValueType<T>() {
    return typeof(T).IsValueType;
}
_

または、型推論のためにサンプルオブジェクトを使用する場合:

_public bool IsValueType<T>(T obj) {
    return typeof(T).IsValueType;
}
_

これはボクシングを必要とせず(GetType()はボクシングです)、_Nullable<T>_に問題はありません。より興味深いケースは、object...を渡すときです。

_ public bool IsValueType(object obj);
_

ここでは、空の_Nullable<T>_(構造体)またはクラスである可能性があるため、nullにはすでに大きな問題があります。しかし、合理的な試みは次のとおりです。

_public bool IsValueType(object obj) {
    return obj != null && obj.GetType().IsValueType;
}
_

ただし、空の_Nullable<T>_ sに対しては正しくない(修正できない)ことに注意してください。ここで、すでにボクシングされているので、ボクシングについて心配することは無意味になります。

89
Marc Gravell

私の最初の答えは、簡単なテストを書いて自分で調べることです。

2番目の答えは(もちろん、自分でテストを行わないで)オプション1です。最も簡単なチェックです。 2番目の方法には2つの個別のチェックが含まれ、3番目の方法には型のデフォルトインスタンスの作成が含まれます。

読みやすさも考慮する必要があります。このフレームワークにより、コード内に次のものを含めることができます。

if(someObj is ValueType)
{
    // Do some work
}

なぜ上記のステートメントを単純に変換するメソッドを作成する必要さえありますか(メソッドを静的にし、コンパイラーがジェネリック型を推論できると仮定した場合):

if(IsValueType(someObj))
{
    // Do some work
}
7
Justin Niessner

構造体を定義すると、実際には2つの型が定義されます。値型と、System.ValueTypeから派生するクラス型です。 System.ValueTypeから派生した型の変数、パラメーター、フィールド、または配列(集合的に「ストレージの場所」)を作成する要求が行われた場合、システムは代わりにオブジェクトのフィールドを保存するストレージの場所を作成しますこれらのフィールドが表示されるオブジェクトへの参照を保存します。一方、System.ValueTypeから派生した型のインスタンスを作成する要求が作成された場合、システムはSystem.ValueTypeから派生したクラスのオブジェクトインスタンスを作成します。

これは、IValueを実装する構造体を作成することで実証できます。

 interface IValue {int value {get; set;}}; 
 struct ValueStruct:IValue 
 {
 public int value {get;セットする;}};
}

一般的なテストルーチンとそれをラップするコード:

 static void Test <T>(T it)ここでT:IValue 
 {
 T duplicate = it; 
 it.value + = 1; 
 duplicate.value + = 10; 
 Console.WriteLine(it.value.ToString()); 
} 
 static void Test()
 {
 ValueStruct v1 = new ValueStruct(); 
 v1.value = 9; 
 IValue v2 = v1; 
 Test <ValueStruct>(v1); 
 Test <ValueStruct>(v1); 
 Test <IValue>(v1); 
 Test <IValue>(v1); 
 Test <IValue>(v2); 
 Test <IValue>(v2); 
} 

いずれの場合も、Testに渡されたパラメーターでGetTypeを呼び出すと、ValueStructが生成され、それ自体が値型として報告されることに注意してください。それにもかかわらず、渡されたアイテムは、最初の2回の呼び出しで「実際の」値タイプになります。 3番目と4番目の呼び出しでは、duplicateへの変更がitに影響するという事実が示すように、実際にはクラス型になります。 5回目と6回目の呼び出しでは、変更がv2に反映されるため、2回目の呼び出しでそれが「表示」されます。

3
supercat
static class Metadata<T>
{
    static public readonly Type Type = typeof(T);
    static public readonly bool IsValueType = Metadata<T>.Type.IsValueType;
}

//fast test if T is ValueType
if(Metadata<T>.IsValueType) //only read static readonly field!
{
    //...
}
2
Teter28

2つのルールがあります。

1-すべてのクラスはreference ObjectやStringなどのタイプであるため、.NET Frameworkでサポートされていますclasses

2-すべての構造は、参照メンバーが含まれている場合でも、boolやcharなどのvalueタイプであるため、.NET Frameworkでサポートされていますstructures

任意のタイプを右クリックし、Go To Definitionクラスの場合は参照タイプ、それがStructの場合は値タイプであることを意味します:)

0
Kasper Roma