2010-09-04 1 views
9

E 'possibile verificare in fase di esecuzione se determinato tipo è il tipo di dati personalizzato o uno dei tipi di dati primitivi di .NET?Come determinare e verificare se un tipo di montaggio è di tipo personalizzato o di tipo primitivo utilizzando la riflessione in .NET?

ho definito tipi definiti dall'utente nell'assemblaggio e quelle di tutti i tipi sono alcune strutture. Ho bisogno di chiamare i metodi di tipi definiti dall'utente di parametri whome sono quelle strutture. Quindi questo deve riempire i dati di conseguenza prima di chiamare quelle funzioni in fase di runtime usando reflection.

Ora Esiste un metodo disponibile in riflessione con la quale siamo in grado di pista che determinato tipo di dati è personalizzato o tipo di dati primitivi. So di attributo isclass, ma i miei tipi di dati definiti dall'utente mirati non sono classi, questi pubblici sono strutture.

+0

'custom' e' primitive' non coprono tutti i tipi di tipi disponibili in .NET - 'stringa', ad esempio, non rientra in nessuna delle categorie. Una divisione come 'fornita dal BCL' /' fornita altrove' o 'primitiva' /' non primitiva' è una suddivisione completa. –

risposta

1
+0

Vale la pena ricordare (come per la mia risposta) che 'IsPrimitive' restituisce false per string, che è un po 'fuorviante a seconda della" tua "definizione di primitive =) – Rob

+0

Con mia sorpresa, lo standard CLI (Ecma-335) usa il termine "tipo primitivo" senza definirlo. Le specifiche del linguaggio C# (Ecma-334), tuttavia, li chiamano "tipi semplici" e definiscono il termine per includere tutti i tipi di valori numerici tra cui 'decimal',' bool' e 'char', ma nessuno dei tipi di riferimento (quindi no 'stringa' e no' oggetto'). – Timwi

0

Una molto semplice, modo rudimentale di determing se un tipo è fornito dal BCL/CLR è:

var type = typeof(int); 
var isSystemType = type.Assembly.FullName.StartsWith("mscorlib"); 

Tenete a mente che l'utilizzo Type.IsPrimitive tornerà falso per System.String, quindi dipende da quale definizione di "primitivo" stai usando se è adatta o meno.

+0

L'idea va bene, ma non sarebbe molto meglio fare 'typeof (int) .Assembly.Equals (candidateType);' o qualcosa del genere? Cosa succede se qualcuno crea "mscorlibextensions"? – Ani

+0

@Ani - Ho detto che era molto semplice e rudimentale! =) – Rob

+0

Tranne quando definisco il mio assembly, "mscorlibex.dll", e questo restituisce true anche per tutti i tipi presenti. Immagino che sia un po 'ridicolo, però, poiché l'unica ragione per cui potrei farlo sarebbe essere subdolo. –

8

mi piacerebbe andare con qualcosa di simile:

static bool IsFundamental(this Type type) 
{ 
    return type.IsPrimitive || type.Equals(typeof(string)) || type.Equals(typeof(DateTime)); 
} 

La scelta di string e DateTime come aggiunte a the types for which IsPrimitive returns true, però, è una questione soggettiva in quanto non esiste un elenco assoluta ... la scelta finale è tua (si potrebbe voler includere decimal così, per esempio); e dovrebbe essere sicuramente essere documentato (almeno in un commento, preferibilmente uno XML).

4

In base alle informazioni in questo question, è possibile eseguire questa utilizzando il seguente codice:

public static class TypeExtensions 
{ 
    private static List<byte[]> tokens = new List<byte[]>() 
    { 
     new byte[] {0xb7, 0x7a, 0x5c, 0x56, 0x19, 0x34, 0xe0, 0x89}, 
     new byte[] {0x31, 0xbf, 0x38, 0x56, 0xad, 0x36, 0x4e, 0x35}, 
     new byte[] {0xb0, 0x3f, 0x5f, 0x7f, 0x11, 0xd5, 0x0a, 0x3a} 
    }; 

    public static bool IsFrameworkType(this Type type) 
    { 
     if (type == null) { throw new ArgumentNullException("type"); } 

     byte[] publicKeyToken = type.Assembly.GetName().GetPublicKeyToken();  

     return publicKeyToken != null && publicKeyToken.Length == 8 
      && tokens.Contains(publicKeyToken, new ByteArrayEqualityComparer()); 
    } 
} 

L'insieme di token di chiave pubblica sono validi per NET 2.0 e superiori (tra cui .NET 4.0). La classe ByteArrayEqualityComparer assomiglia:

public class ByteArrayEqualityComparer : EqualityComparer<byte[]> 
{ 
    public override bool Equals(byte[] x, byte[] y) 
    { 
     return x != null && y != null 
        && x.Length == 8 && y.Length == 8 
        && x[0] == y[0] 
        && x[1] == y[1] 
        && x[2] == y[2] 
        && x[3] == y[3] 
        && x[4] == y[4] 
        && x[5] == y[5] 
        && x[6] == y[6] 
        && x[7] == y[7]; 
    } 

    public override int GetHashCode(byte[] obj) 
    { 
     return obj.GetHashCode(); 
    } 
} 

Si potrebbe quindi utilizzare questo metodo come:

Debug.WriteLine("Is type `string` a .NET Framework type? {0}", 
    typeof(string).IsFrameworkType()); 
0

Sembra che avete la necessità di distinguere tra i tipi che avete fatto voi da tutto il resto. Basta creare un attributo personalizzato che si mette su ognuno dei tipi, come questo:

[CustomAttribute] 
struct MyDataType 
{ 
.... 
} 

Un'altra opzione è quella di creare un'interfaccia che tutti i propri tipi personalizzati attrezzo. Quindi è facile vedere se è necessario fare qualcosa di speciale con quell'istanza facendo semplicemente if (x is ICustom) ....

Se è possibile inserirli tutti nello stesso spazio dei nomi o assieme, è anche facile controllarli con il riflesso.

+0

Il problema con questo approccio è che tu (e tutti i membri del tuo team) devi ricordare di aggiungere questo attributo a ogni tipo mai creato. Questo alla fine porterà a mal di testa di manutenzione quando qualcuno si dimentica di farlo e le cose iniziano a comportarsi male. –

+0

Scott: È molto meglio affidarsi a qualcosa sotto il proprio controllo piuttosto che usare una certa euristica che si basa su MS che non cambia qualcosa nella prossima versione. – Gabe

+0

Presenta ancora un grave incubo di manutenzione a lungo termine. Le possibilità che Microsoft modifichi i token delle chiavi pubbliche nelle versioni successive del framework sono ridotte sebbene ciò possa accadere. –

0

Potreste essere in grado di cavarsela, controllando il nome completo del tipo o l'assemblea come sotto,

if(obj.GetType().Assembly.FullName.Contains("MyAssembly")) 
{ 
    //User-defined type 
} 
else if(obj.GetType().FullName.StartsWith("System.")) 
{ 
    //.NET type 
} 
0

Il modo più semplice che ho seguito è quello di verificare lo spazio dei nomi per capire se il suo uno dei i tuoi tipi personalizzati Ad esempio, lo spazio dei nomi potrebbe essere "YourCompany.YourDepartment" e questo può essere verificato rispetto allo spazio dei nomi del tipo.