web-dev-qa-db-fra.com

Le moyen le plus efficace de vérifier si un objet est un type de valeur

ATTENTION: CE CODE SUCE, VOIR LES COMMENTAIRES D'ANTONY

Lequel est plus vite?

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. autre chose

41
smartcaveman

Vous ne testez pas vraiment un objet - vous voulez tester le type. Pour les appeler, l'appelant doit connaître le type, mais ... meh. Étant donné une signature <T>(T obj) la seule réponse sensée est:

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

ou si nous voulons utiliser un exemple d'objet à des fins d'inférence de type:

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

cela n'a pas besoin de boxe (GetType() est boxe), et n'a pas de problème avec Nullable<T>. Un cas plus intéressant est lorsque vous passez object...

 public bool IsValueType(object obj);

ici, nous avons déjà d'énormes problèmes avec null, car cela pourrait être un Nullable<T> (une structure) ou une classe vide. Mais une tentative raisonnable serait:

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

mais notez qu'il est incorrect (et non réparable) pour les Nullable<T> vides. Ici, il devient inutile de s'inquiéter de la boxe car nous sommes déjà boxés.

89
Marc Gravell

Ma première réponse serait d'écrire un test simple et de le découvrir par vous-même.

Ma deuxième réponse (sans aucun test de ma part, bien sûr) serait option 1. C'est la vérification la plus simple. La deuxième méthode implique deux vérifications distinctes tandis que la troisième implique la création d'une instance par défaut d'un type.

Vous devez également considérer la lisibilité. Le framework vous donne déjà la possibilité d'avoir les éléments suivants dans votre code:

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

Pourquoi même prendre la peine de créer une méthode qui transformerait simplement l'instruction ci-dessus en (en supposant que vous avez rendu votre méthode statique et autorisé le compilateur à déduire le type générique):

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

La définition d'une structure définit en fait deux types: un type de valeur et un type de classe qui dérive de System.ValueType. Si une demande est faite pour créer une variable, un paramètre, un champ ou un tableau (collectivement, "emplacement de stockage") d'un type qui dérive de System.ValueType, le système créera à la place un emplacement de stockage qui stockera les champs de l'objet plutôt que stocker une référence à un objet dans lequel ces champs apparaissent. D'un autre côté, si une demande est faite pour créer une instance d'un type dérivant de System.ValueType, le système créera une instance d'objet d'une classe qui dérive de System.ValueType.

Cela peut être démontré en créant une structure qui implémente IValue:

 interface IValue {int value {get; set;}}; 
 struct ValueStruct: IValue 
 {
 public int value {get; ensemble;}};
}

avec une routine de test générique et du code pour l'envelopper:

 test de vide statique <T> (T it) où T: IValue 
 {
 T duplicate = it; 
 it.value + = 1; 
 duplicate.value + = 10; 
 Console.WriteLine (it.value.ToString ()); 
} 
 test de vide statique () 
 {
 ValueStruct v1 = nouveau 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); 
} 

Notez que dans tous les cas, appeler GetType sur le paramètre passé à Test produirait ValueStruct, qui se rapportera comme un type de valeur. Néanmoins, l'élément transmis ne sera un type de valeur "réel" que lors des deux premiers appels. Lors des troisième et quatrième appels, ce sera vraiment un type de classe, comme le montre le fait qu'une modification de duplicate affectera it. Et lors des cinquième et sixième appels, le changement sera propagé vers la v2, donc le deuxième appel le "verra".

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

Il y a deux règles:

1-Toutes les classes sont des types référence tels que Object et String, elles sont donc prises en charge par .NET Framework classes.

2-Toutes les structures sont de type valeur telles que bool et char, même si elles contiennent un membre de référence, elles sont donc prises en charge par .NET Framework structures.

Faites simplement un clic droit sur n'importe quel type et Aller à la définition s'il s'agit d'une classe, ce qui signifie qu'il s'agit d'un type de référence, sinon s'il s'agit d'un Struct, ce qui signifie qu'il s'agit d'un type de valeur :)

0
Kasper Roma