51 votes

La manière la plus efficace de vérifier si un objet est un type de valeur

AVERTISSEMENT : CE CODE EST NUL, VOIR LES COMMENTAIRES D'ANTHONY

Lequel est le plus rapide ?

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

3 votes

La performance est-elle vraiment importante, car il s'agit en fait d'une micro-optimisation ?

6 votes

Les méthodes 2 et 3, telles qu'elles sont rédigées, ne sont pas valables. obj == null || renvoie un résultat positif pour les types de référence. default(T) != null renverra un message faux pour l'élément Nullable<T> des structures.

4 votes

Votre modification de la méthode 2 ne sera toujours pas valable. obj != null || renvoie un résultat positif pour les objets de type référence non nuls.

104voto

Marc Gravell Points 482669

Vous ne testez pas vraiment un objet - vous voulez tester la fonction 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 la suivante :

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;
}

il n'est pas nécessaire de le mettre en boîte ( GetType() est la boxe), et n'a pas de problèmes avec les Nullable<T> . Un cas plus intéressant est celui où vous passez object ...

 public bool IsValueType(object obj);

ici, nous avons déjà d'énormes problèmes avec les null puisqu'il pourrait s'agir d'un Nullable<T> (une structure) ou une classe. Mais une tentative raisonnable serait :

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

mais notez qu'elle est incorrecte (et non corrigeable) dans le cas de Nullable<T> s. Il devient alors inutile de se préoccuper de l'encadrement, puisque nous sommes déjà encadrés.

8voto

Justin Niessner Points 144953

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 entendu) serait la suivante option 1 . Il s'agit du contrôle le plus simple. La deuxième méthode implique deux vérifications distinctes, tandis que la troisième consiste à créer une instance par défaut d'un type.

Vous devez également tenir compte de 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 se donner la peine de créer une méthode qui transformerait simplement l'énoncé ci-dessus en (en supposant que vous ayez rendu votre méthode statique et permis au compilateur de déduire le type générique) :

if(IsValueType(someObj))
{
    // Do some work
}

3voto

supercat Points 25534

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 dérivé de System.ValueType, le système créera un emplacement de stockage qui stockera les champs de l'objet plutôt qu'une référence à un objet dans lequel ces champs apparaissent. En revanche, 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 dérivant de System.ValueType.

Pour s'en convaincre, il suffit de créer une structure qui implémente IValue :

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

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

static void Test<T>(T it) where 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);
}

Notez que dans tous les cas, l'appel à GetType sur le paramètre passé à Test produirait ValueStruct, qui se déclarerait lui-même comme un type de valeur. Néanmoins, l'élément passé ne sera un "vrai" type de valeur que lors des deux premiers appels. Lors des troisième et quatrième appels, il s'agira en réalité d'un type de classe, comme le montre le fait qu'une modification de duplicate affectera it . Lors des cinquième et sixième appels, la modification sera propagée à la v2, de sorte que le deuxième appel la "verra".

3voto

Teter28 Points 484
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!
{
    //...
}

0 votes

La limite de cette méthode est qu'elle est basée sur typeof(T) plutôt que de tester une instance entrante. En général, un programmeur sait si un type est une valeur ou non, le besoin commun est de savoir si une valeur est une valeur. instance est une valeur ou non. Considérons un paramètre de méthode object obj . Cette réponse évaluera cela sur la base de T=object le type de paramètre déclaré, et non le type d'exécution d'une instance spécifique, et renverra donc false Quoi qu'il en soit obj est. Mais obj pourrait être un en boîte entier ou autre type de valeur.

0voto

Kasper Roma Points 102

Il existe deux règles :

1-Toutes les classes sont référence tels que Object et String, de sorte qu'il est pris en charge par .NET Framework classes .

2-Toutes les structures sont valeur tels que bool et char, même s'il contient un membre de référence, il est donc pris en charge par le .NET Framework structures .

Il suffit de cliquer avec le bouton droit de la souris sur n'importe quel type et Aller à la définition si c'est une classe, cela signifie que c'est un type de référence sinon si c'est une structure, cela signifie que c'est un type de valeur :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X