2010-03-14 13 views
127

Ho un blocco di codice che serializza un tipo in un tag HTML.Come verificare se il tipo è primitivo

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

Questa grande opera, tranne che voglio fare solo questo per i tipi primitivi, come int, double, bool ecc, e di altri tipi che non sono primitive, ma può essere serializzato facilmente come string. Voglio che ignori tutto il resto come gli elenchi & altri tipi personalizzati.

Qualcuno può suggerire come faccio? O devo specificare i tipi che voglio consentire da qualche parte e attivare il tipo di proprietà per vedere se è permesso? È un po 'complicato, quindi sarebbe bello se io avessi un modo più ordinato.

+10

'System.String' non è un tipo primitivo. – SLaks

+2

Il modo migliore per farlo è non usare affatto i generici. Se si supporta un numero limitato di tipi come tipi di parametri legali, è sufficiente disporre di molti sovraccarichi. Se si supporta qualsiasi tipo che implementa ISerializable, quindi scrivere un metodo non generico che richiede ISerializable. Usa i generici per cose che sono in realtà * generiche *; se il tipo conta davvero, probabilmente non è generico. –

+0

@Eric: Grazie, mi chiedo anche se è possibile utilizzare gli stessi criteri con i numeri? Ad esempio, per scrivere funzioni matematiche che supportano tutti i tipi numerici, cioè Media, Somma, ecc.Dovrebbero essere implementati usando generici o sovraccarichi? Importa se l'implementazione è la stessa o no? Perché è praticamente la stessa operazione per Average, Sum per qualsiasi tipo numerico, giusto? –

risposta

140

È possibile utilizzare la proprietà Type.IsPrimitive, ma fate attenzione perché ci sono alcuni tipi che possiamo pensare che sono primitivi, ma ITA, ad esempio Decimal e String.

Edit 1:Aggiunto codice di esempio

Ecco un codice di esempio:

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

Edit 2: Come @SLaks commenti, ci sono altri tipi che forse si desidera trattare anche come primitivi. Penso che dovrai aggiungere queste variazioni una alla volta.

Edit 3: IsPrimitive = (booleano, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, doppio e singolo), Antera tipo primitivo-Like per verificare (t == typeof (DateTime))

+10

E forse 'DateTime',' TimeSpan' e 'DateTimeOffset'. – SLaks

+0

Mmmm ... sì, hai ragione. Penso che dovremo aggiungere altre possibilità – Javier

+2

È necessario utilizzare il logico o ('||'), non il bit a bit o ('|'). – SLaks

3

Supponendo di avere una firma funzione come questa:

void foo<T>() 

si potrebbe aggiungere un vincolo generico per consentire i tipi di valore solo:

void foo<T>() where T : struct 

Si noti che questo consente non solo i tipi primitivi per T, ma qualsiasi tipo di valore.

45

Ho appena trovato questa domanda mentre cercavo una soluzione simile e ho pensato che potreste essere interessati al seguente approccio usando System.TypeCode e System.Convert.

E 'facile da serializzare qualsiasi tipo che viene mappato a un System.TypeCode diverso System.TypeCode.Object, così si potrebbe fare:

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

Il vantaggio di questo approccio è che non c'è bisogno di nominare tutti gli altri non accettabile -primitivo tipo. È inoltre possibile modificare leggermente il codice precedente per gestire qualsiasi tipo che implementa IConvertible.

+2

Questo è fantastico, ho dovuto aggiungere manualmente 'Guid' per i miei scopi (come primitivo nella mia definizione). –

37

lo facciamo in questo modo nel nostro ORM:

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

So che usando IsValueType non è l'opzione migliore (si può avere il proprio le strutture molto complesse) ma funziona nel 99% dei casi

+5

Perché hai bisogno di IsPrimitive se stai utilizzando IsValueType? Non sono tutti i tipi di valore primitivi? – JoelFan

+4

@JoelIl tipo decimale ha IsPrimitive false, ma IsValueType true – xhafan

+1

@xhafan: rispondi alla domanda sbagliata. Tutte le strutture sono come 'decimal' in questo senso. Ma esiste un tipo per cui 'IsPrimitive' restituisce' true' ma 'IsValueType' restituisce' false'? Se non esiste un tale tipo, il test 't.IsPrimitive' non è necessario. – Lii

1

Questo è quello che ho nella mia biblioteca. I commenti sono i benvenuti

Controllo innanzitutto IsValueType, poiché gestisce la maggior parte dei tipi, quindi String, poiché è il secondo più comune. Non riesco a pensare a un primitivo che non sia un tipo di valore, quindi non so se quella gamba del mai se verrà colpita.

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 

Allora posso usare in questo modo:

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 
12

Ecco come ho fatto.

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

Aggiungerei anche Guid, ma è una bella lista – Marco

+2

Bel lavoro su quello. –

2

Avevo bisogno di serializzare i tipi allo scopo di esportarli in XML. Per fare ciò, ho iterato l'oggetto e ho optato per i campi che erano primitivi, enum, tipi di valori o serializzabili. Questo è stato il risultato della mia interrogazione:

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

ho usato LINQ per scorrere i tipi, quindi ottenere il loro nome e il valore da memorizzare in una tabella di simboli. La chiave è nella clausola 'where' che ho scelto per la riflessione. Ho scelto tipi di valori primitivi, enumerati, e serializzabili. Ciò consentiva l'arrivo di stringhe e oggetti DateTime come previsto.

Cheers!

5

anche una buona possibilità:

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

Ogni istanza di 'Tipo' ha una proprietà chiamata [IsPrimitive] (http://msdn.microsoft.com/en-us/library/system.type.isprimitive.aspx). Dovresti invece usarlo. – Renan

+3

Né 'String' né' Decimal' sono primitive. – k3flo

+0

Funziona per me, ma ho rinominato IsClrType per non confondere il suo significato con l'esistente .IsPrimitive sulla classe Type – KnarfaLingus

1

Voglio solo condividere la mia soluzione. Forse è utile a chiunque.

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

'IsPrimitiveType (typeof (System.AccessViolationException)) == true' –

+2

' namespace System {class MyNonPrimitiveType {}} ' –

0
public static bool IsPrimitiveType(object myObject) 
{ 
    var myType = myObject.GetType(); 
    return myType.IsPrimitive || myType.Namespace == null || myType.Namespace.Equals("System"); 
} 

Non dimenticare di controllare namespace NULL, perché gli oggetti anonimi non hanno assegnato namespace

18

Dalla risposta @Ronnie Overby e commentare @jonathanconway, ho scritto questo metodo che funziona per Nullable ed esclude le strutture utente.

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

Con la seguente TestCase:

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

Qui è un'altra opzione praticabile.

public static bool CanDirectlyCompare(Type type) 
{ 
    return typeof(IComparable).IsAssignableFrom(type) || type.IsPrimitive || type.IsValueType; 
} 
Problemi correlati