2010-09-04 2 views
9

Ist es möglich, zur Laufzeit zu überprüfen, ob der angegebene Datentyp Custom oder einer der primitiven Datentypen von .NET ist?Wie zu bestimmen und zu überprüfen, ob ein Typ in Assembly benutzerdefinierten Typ oder primitiven Typ ist, der Reflektion in .NET verwendet?

Ich habe benutzerdefinierte Typen in Assembly definiert und diese alle Typen sind einige Strukturen. Ich muss die Methoden der benutzerdefinierten Typen aufrufen, deren Parameter diese Strukturen sind. Daher müssen die Daten entsprechend gefüllt werden, bevor diese Funktionen zur Laufzeit über Reflektion aufgerufen werden.

Jetzt Gibt es eine Methode in der Reflexion, mit der wir verfolgen können, ob der angegebene Datentyp benutzerdefinierter oder primitiver Datentyp ist. Ich kenne das IsClass-Attribut, aber meine angepeilten benutzerdefinierten Datentypen sind keine Klassen, diese öffentlichen sind STRUKTUREN.

+0

'custom' und' primitive' decken nicht alle in .NET verfügbaren Typen ab - 'string' beispielsweise passt in keine der Kategorien. Eine Division wie 'von der BCL bereitgestellt '/' anderswo bereitgestellt 'oder' primitiv '/' nicht primitiv 'ist eine vollständige Unterteilung. –

Antwort

1
+0

Es ist erwähnenswert (nach meiner Antwort), dass "IsPrimitive" false für String zurückgibt, was ein bisschen falsch ist, abhängig von "Ihrer" Definition von primitive =) – Rob

+0

Zu meiner Überraschung verwendet der CLI-Standard (Ecma-335) der Begriff "primitiver Typ", ohne ihn zu definieren. Die C# -Sprachspezifikation (Ecma-334) nennt sie jedoch "einfache Typen" und definiert den Begriff so, dass er alle numerischen Werttypen einschließlich "dezimal", "bool" und "char" enthält, aber keinen der Referenztypen (z kein 'String' und kein' Objekt'). – Timwi

0

Eine sehr einfache, rudimentäre Weise, ob eine Art von determing vom BCL/CLR ist vorgesehen:

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

Beachten Sie, dass Type.IsPrimitive mit falschen für System.String zurück, Es hängt also davon ab, welche Definition von "primitiv" Sie verwenden, ob es geeignet ist oder nicht.

+0

Die Idee ist in Ordnung, aber wäre es nicht viel besser zu tun 'typeof (int) .Assembly.Equals (candidateType);' oder etwas? Was, wenn jemand 'mscorlibextensions' erstellt? – Ani

+0

@Ani - Ich habe gesagt, es war sehr einfach und rudimentär! =) – Rob

+0

Mit Ausnahme, wenn ich meine eigene Assembly "mscorlibex.dll" definiere, und dies gibt auch für alle darin enthaltenen Typen true zurück. Ich denke, das ist ein lächerlicher Punkt, denn der einzige Grund, warum ich das tun könnte, wäre hinterhältig zu sein. –

8

ich mit so etwas wie gehen würde:

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

Die Wahl der string und DateTime als Ergänzungen the types for which IsPrimitive returns true jedoch eine subjektive Angelegenheit ist, da es keine absolute Liste ist ... ist die ultimative Wahl liegt bei Ihnen (Sie könnten zum Beispiel auch decimal einschließen); und es sollte definitiv dokumentiert werden (zumindest in einem Kommentar, vorzugsweise einem XML).

4

Basierend auf Informationen in diesen question, können Sie dies mit dem folgenden Code auszuführen:

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

Der Satz von Public-Key-Token gültig sind für .NET 2.0 und höher (einschließlich .NET 4.0). Die ByteArrayEqualityComparer Klasse wie folgt aussieht:

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

Sie dann diese Methode wie verwenden würde:

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

Es klingt wie Sie einen Bedarf zwischen verschiedenen Arten zu unterscheiden, die Sie sich von allem anderen gemacht. Erstellen Sie einfach ein benutzerdefiniertes Attribut, das Sie auf jedem Ihrer Typen setzen, wie folgt aus:

[CustomAttribute] 
struct MyDataType 
{ 
.... 
} 

Eine weitere Option ist eine Schnittstelle zu erstellen, die alle Ihre eigenen Typen implementieren. Dann ist es einfach zu sehen, ob Sie mit dieser Instanz etwas Besonderes tun müssen, indem Sie einfach if (x is ICustom) ... tun.

Wenn es möglich ist, alle im selben Namensraum oder in derselben Baugruppe zu platzieren, können diese auch einfach mit Reflektion überprüft werden.

+0

Das Problem bei diesem Ansatz ist, dass Sie (und jeder in Ihrem Team) daran denken müssen, dieses Attribut zu jedem Typ hinzuzufügen, der jemals erstellt wurde. Dies wird letztendlich zu Kopfschmerzen führen, wenn jemand dies vergisst und die Dinge beginnen sich schlecht zu benehmen. –

+0

Scott: Es ist viel besser, sich auf etwas unter Ihrer eigenen Kontrolle zu verlassen, als eine Heuristik zu verwenden, die darauf beruht, dass MS in der nächsten Version nichts ändert. – Gabe

+0

Es stellt auf lange Sicht immer noch einen großen Wartungsalptraum dar. Die Chancen, dass Microsoft in späteren Versionen des Frameworks die öffentlichen Schlüssel-Token ändert, sind gering, auch wenn dies passieren könnte. –

0

Sie könnten in der Lage sein, durch zu bekommen, indem Sie den vollständigen Namen des Typs Überprüfung oder die Baugruppe, wie unten,

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

Der einfachste Weg, ich gefolgt ist, den Namensraum zu überprüfen, ob es ist eines, um herauszufinden, Ihre benutzerdefinierten Typen. Zum Beispiel könnte Ihr Namespace "YourCompany.YourDepartment" sein und dies kann mit dem Namespace des Typs verifiziert werden.

Verwandte Themen