web-dev-qa-db-fra.com

Comment vérifier si le type est primitif

J'ai un bloc de code qui sérialise un type dans une balise HTML.

Type t = typeof(T); // I pass <T> in as a paramter, where myObj is of type T
tagBuilder.Attributes.Add("class", t.Name);
foreach (PropertyInfo prop in t.GetProperties())
{
    object propValue = prop.GetValue(myObj, null);
    string stringValue = propValue != null ? propValue.ToString() : String.Empty;
    tagBuilder.Attributes.Add(prop.Name, stringValue);
}

Cela fonctionne très bien, sauf que je ne souhaite le faire que pour les types primitifs, comme int, double, bool etc., et d’autres types qui ne sont pas primitifs mais peuvent l'être. sérialisé facilement comme string. Je veux qu'il ignore tout le reste, comme les listes et autres types personnalisés.

Quelqu'un peut-il suggérer comment je fais cela? Ou dois-je spécifier les types que je veux autoriser quelque part et activer le type de la propriété pour voir s'il est autorisé? C'est un peu brouillon, alors ce serait bien si je faisais mieux.

150
DaveDev

Vous pouvez utiliser la propriété Type.IsPrimitive, mais soyez prudent, car nous pouvons penser que certains types sont des primitives, mais ils ne le sont pas, par exemple Decimal et String.

Edition 1: Exemple de code ajouté

Voici un exemple de code:

if (t.IsPrimitive || t == typeof(Decimal) || t == typeof(String) || ... )
{
    // Is Primitive, or Decimal, or String
}

Edit 2: Comme @ SLaks , il existe d'autres types que vous souhaitez peut-être traiter comme des primitives. Je pense que vous devrez ajouter ces variations une par une.

Modifier 3: IsPrimitive = (Boolean, Octet, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double, et Simple), type Anther Primitive-Like à vérifier (t == typeof (DateTime))

169
Javier

Je viens de trouver cette question tout en recherchant une solution similaire, et je pensais que l’approche suivante utilisant la méthode System.TypeCode et System.Convert.

Il est facile de sérialiser tout type mappé sur un System.TypeCode autre que System.TypeCode.Object, alors tu pourrais faire:

object PropertyValue = ...
if(Convert.GetTypeCode(PropertyValue) != TypeCode.Object)
{
    string StringValue = Convert.ToString(PropertyValue);
    ...
}

L'avantage de cette approche est que vous n'avez pas à nommer tous les autres types non primitifs acceptables. Vous pouvez également modifier légèrement le code ci-dessus pour gérer tout type implémentant IConvertible.

51
Michael Petito

Nous le faisons comme ça dans notre ORM:

Type t;
bool isPrimitiveType = t.IsPrimitive || t.IsValueType || (t == typeof(string));

Je sais que l'utilisation de IsValueType n'est pas la meilleure option (vous pouvez avoir vos propres structures très complexes), mais cela fonctionne dans 99% des cas (et inclut Nullables).

46
Alex

À partir de la réponse @Ronnie Overby et du commentaire @jonathanconway, j'ai écrit cette méthode qui fonctionne pour Nullable et qui exclut les structures utilisateur.

public static bool IsSimpleType(Type type)
{
    return
        type.IsPrimitive ||
        new Type[] {
            typeof(Enum),
            typeof(String),
            typeof(Decimal),
            typeof(DateTime),
            typeof(DateTimeOffset),
            typeof(TimeSpan),
            typeof(Guid)
        }.Contains(type) ||
        Convert.GetTypeCode(type) != TypeCode.Object ||
        (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>) && IsSimpleType(type.GetGenericArguments()[0]))
        ;
}

Avec le TestCase suivant:

struct TestStruct
{
    public string Prop1;
    public int Prop2;
}

class TestClass1
{
    public string Prop1;
    public int Prop2;
}

[Test]
public void Test1()
{
    Assert.IsTrue(IsSimpleType(typeof(Enum)));
    Assert.IsTrue(IsSimpleType(typeof(String)));
    Assert.IsTrue(IsSimpleType(typeof(Char)));
    Assert.IsTrue(IsSimpleType(typeof(Guid)));

    Assert.IsTrue(IsSimpleType(typeof(Boolean)));
    Assert.IsTrue(IsSimpleType(typeof(Byte)));
    Assert.IsTrue(IsSimpleType(typeof(Int16)));
    Assert.IsTrue(IsSimpleType(typeof(Int32)));
    Assert.IsTrue(IsSimpleType(typeof(Int64)));
    Assert.IsTrue(IsSimpleType(typeof(Single)));
    Assert.IsTrue(IsSimpleType(typeof(Double)));
    Assert.IsTrue(IsSimpleType(typeof(Decimal)));

    Assert.IsTrue(IsSimpleType(typeof(SByte)));
    Assert.IsTrue(IsSimpleType(typeof(UInt16)));
    Assert.IsTrue(IsSimpleType(typeof(UInt32)));
    Assert.IsTrue(IsSimpleType(typeof(UInt64)));

    Assert.IsTrue(IsSimpleType(typeof(DateTime)));
    Assert.IsTrue(IsSimpleType(typeof(DateTimeOffset)));
    Assert.IsTrue(IsSimpleType(typeof(TimeSpan)));

    Assert.IsFalse(IsSimpleType(typeof(TestStruct)));
    Assert.IsFalse(IsSimpleType(typeof(TestClass1)));

    Assert.IsTrue(IsSimpleType(typeof(Nullable<Char>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Guid>)));

    Assert.IsTrue(IsSimpleType(typeof(Nullable<Boolean>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Byte>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Int16>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Int32>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Int64>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Single>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Double>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<Decimal>)));

    Assert.IsTrue(IsSimpleType(typeof(Nullable<SByte>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<UInt16>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<UInt32>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<UInt64>)));

    Assert.IsTrue(IsSimpleType(typeof(Nullable<DateTime>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<DateTimeOffset>)));
    Assert.IsTrue(IsSimpleType(typeof(Nullable<TimeSpan>)));

    Assert.IsFalse(IsSimpleType(typeof(Nullable<TestStruct>)));
}
28
Xav987

Voici comment je l'ai fait.

   static class PrimitiveTypes
   {
       public static readonly Type[] List;

       static PrimitiveTypes()
       {
           var types = new[]
                          {
                              typeof (Enum),
                              typeof (String),
                              typeof (Char),
                              typeof (Guid),

                              typeof (Boolean),
                              typeof (Byte),
                              typeof (Int16),
                              typeof (Int32),
                              typeof (Int64),
                              typeof (Single),
                              typeof (Double),
                              typeof (Decimal),

                              typeof (SByte),
                              typeof (UInt16),
                              typeof (UInt32),
                              typeof (UInt64),

                              typeof (DateTime),
                              typeof (DateTimeOffset),
                              typeof (TimeSpan),
                          };


           var nullTypes = from t in types
                           where t.IsValueType
                           select typeof (Nullable<>).MakeGenericType(t);

           List = types.Concat(nullTypes).ToArray();
       }

       public static bool Test(Type type)
       {
           if (List.Any(x => x.IsAssignableFrom(type)))
               return true;

           var nut = Nullable.GetUnderlyingType(type);
           return nut != null && nut.IsEnum;
       }
   }
15
Ronnie Overby

Aussi une bonne possibilité:

private static bool IsPrimitiveType(Type type)
{
    return (type == typeof(object) || Type.GetTypeCode(type) != TypeCode.Object);
}
5
k3flo

En supposant que vous ayez une signature de fonction comme celle-ci:

void foo<T>() 

Vous pouvez ajouter une contrainte générique pour autoriser uniquement les types de valeur:

void foo<T>() where T : struct

Notez que cela autorise non seulement les types primitifs pour T, mais tout type de valeur.

3
eWolf

J'ai eu besoin de sérialiser des types dans le but de les exporter au format XML. Pour ce faire, j'ai itéré à travers l'objet et j'ai opté pour des champs de type primitif, enum, valeur ou sérialisable. C'était le résultat de ma requête:

Type contextType = context.GetType();

var props = (from property in contextType.GetProperties()
                         let name = property.Name
                         let type = property.PropertyType
                         let value = property.GetValue(context,
                                     (BindingFlags.GetProperty | BindingFlags.GetField | BindingFlags.Public),
                                     null, null, null)
                         where (type.IsPrimitive || type.IsEnum || type.IsValueType || type.IsSerializable)
                         select new { Name = name, Value = value});

J'ai utilisé LINQ pour parcourir les types, puis obtenir leur nom et leur valeur à stocker dans une table de symboles. La clé se trouve dans la clause "où" que j'ai choisie pour la réflexion. J'ai choisi des types de valeur primitifs, énumérés, sérialisables. Cela a permis aux chaînes et aux objets DateTime de passer comme je le souhaitais.

À votre santé!

2
JFalcon

Je veux juste partager ma solution. C'est peut-être utile à n'importe qui.

public static bool IsPrimitiveType(Type fieldType)
{
   return fieldType.IsPrimitive || fieldType.Namespace.Equals("System");
}
1
Bahamut

C'est ce que j'ai dans ma bibliothèque. Les commentaires sont les bienvenus.

Je vérifie d'abord IsValueType, car il gère la plupart des types, puis String, puisqu'il s'agit du deuxième plus courant. Je ne peux pas penser à un primitif qui n'est pas un type de valeur, donc je ne sais pas si cette partie du si est jamais touchée.

  Public Shared Function IsPersistable(Type As System.Type) As Boolean
    With TypeInformation.UnderlyingType(Type)
      Return .IsValueType OrElse Type = GetType(String) OrElse .IsPrimitive
    End With
  End Function

  Public Shared Function IsNullable(ByVal Type As System.Type) As Boolean
    Return (Type.IsGenericType) AndAlso (Type.GetGenericTypeDefinition() Is GetType(Nullable(Of )))
  End Function

  Public Shared Function UnderlyingType(ByVal Type As System.Type) As System.Type
    If IsNullable(Type) Then
      Return Nullable.GetUnderlyingType(Type)
    Else
      Return Type
    End If
  End Function

Ensuite, je peux l'utiliser comme ça:

  Public Shared Function PersistableProperties(Item As System.Type) As IEnumerable(Of System.Reflection.PropertyInfo)
    Return From PropertyInfo In Item.GetProperties()
                     Where PropertyInfo.CanWrite AndAlso (IsPersistable(PropertyInfo.PropertyType))
                     Select PropertyInfo
  End Function
1
toddmo

Voici une autre option viable.

public static bool CanDirectlyCompare(Type type)
{
    return typeof(IComparable).IsAssignableFrom(type) || type.IsPrimitive || type.IsValueType;
}
0
user2023116
public static bool IsPrimitiveType(object myObject)
{
   var myType = myObject.GetType();
   return myType.IsPrimitive || myType.Namespace == null ||  myType.Namespace.Equals("System");
}

N'oubliez pas de vérifier l'espace de noms NULL, car les objets anonymes n'ont pas d'espace de noms attribué.

0
iDusko