2010-09-04 17 views
9

¿Es posible verificar en tiempo de ejecución si el tipo dado es Tipo de datos personalizado o uno de los tipos de datos primitivos de .NET?¿Cómo determinar y verificar si un tipo en el ensamblaje es tipo personalizado o tipo primitivo usando reflexión en .NET?

He definido tipos definidos por el usuario en el ensamblaje y esos todos los tipos son algunas estructuras. Necesito llamar a los métodos de tipos definidos por el usuario cuyos parámetros son esas estructuras. Entonces, esto necesita llenar los datos en consecuencia antes de llamar a esas funciones en tiempo de ejecución usando reflexión.

Ahora ¿Hay algún método disponible en la reflexión por el cual podamos rastrear que el tipo de dato dado sea personalizado o primitivo? Conozco el atributo IsClass, pero mis tipos de datos definidos como definidos por el usuario no son clases, estos públicos son STRUCTS.

+0

'custom' y' primitive' no cubre todos los tipos de tipos disponibles en .NET - 'string', por ejemplo, no encaja en ninguna de las categorías. Una división como 'proporcionada por el BCL' /' proporcionada en otro lugar' o 'primitiva' /' no primitiva' es una subdivisión completa. –

Respuesta

1
+0

Vale la pena mencionar (según mi respuesta) que 'IsPrimitive' devuelve false para cadena, lo cual es un poco erróneo según" tu "definición de primitiva =) – Rob

+0

Para mi sorpresa, el estándar CLI (Ecma-335) utiliza el término "tipo primitivo" sin definirlo. La especificación del lenguaje C# (Ecma-334), sin embargo, los llama "tipos simples" y define el término para incluir todos los tipos de valores numéricos, incluidos 'decimal',' bool' y 'char', pero ninguno de los tipos de referencia (por lo no 'cadena' y no' objeto'). – Timwi

0

Una forma muy sencilla, rudimentario de determing si un tipo es proporcionada por el BCL/CLR es:

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

Tenga en cuenta que el uso de Type.IsPrimitive volverá falsa para System.String, por lo tanto, depende de la definición de "primitivo" que esté utilizando para determinar si es adecuado o no.

+0

La idea está bien, pero ¿no sería mucho mejor hacer 'typeof (int) .Assembly.Equals (candidateType);' o algo así? ¿Qué pasa si alguien crea 'mscorlibextensions'? – Ani

+0

@Ani - ¡Dije que era muy simple y rudimentario! =) – Rob

+0

Excepto cuando defino mi propio ensamblaje, "mscorlibex.dll", y esto también devuelve verdadero para todos los tipos. Sin embargo, supongo que es un punto ridículo, ya que la única razón por la que podría hacer eso sería ser sigiloso. –

8

me gustaría ir con algo como:

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

La elección de string y DateTime como adiciones a the types for which IsPrimitive returns true, sin embargo, es una cuestión subjetiva ya que no hay lista de absoluta ... la mejor elección es suya (es posible que desee incluir decimal también, por ejemplo); y debería definitivamente estar documentado (al menos en un comentario, preferiblemente en uno XML).

4

Sobre la base de la información en este question, se puede lograr esto usando el siguiente código:

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

El conjunto de tokens de clave pública son válidos para .NET 2.0 y superior (incluyendo .NET 4.0). La clase ByteArrayEqualityComparer parece:

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

A continuación, utilizar este método como:

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

Parece que usted tiene una necesidad de distinguir entre los tipos que ha realizado a sí mismo de todo lo demás. Basta con crear un atributo personalizado que se pone en cada uno de sus tipos, así:

[CustomAttribute] 
struct MyDataType 
{ 
.... 
} 

Otra opción es crear una interfaz que todos sus propios tipos de implementar. Entonces es fácil ver si necesita hacer algo especial con esa instancia simplemente haciendo if (x is ICustom) ....

Si es posible ponerlos todos en el mismo espacio de nombres o ensamblaje, también son fáciles de verificar con la reflexión.

+0

El problema con este enfoque es que usted (y todos los integrantes de su equipo) deben recordar agregar este atributo a cada tipo que se haya creado. Esto finalmente llevará a dolores de cabeza de mantenimiento cuando alguien se olvida de hacer esto y las cosas comienzan a comportarse mal. –

+0

Scott: Es mucho mejor confiar en algo bajo tu propio control que usar alguna heurística que dependa de que MS no cambie nada en la próxima versión. – Gabe

+0

Todavía presenta una gran pesadilla de mantenimiento a largo plazo. Las posibilidades de que Microsoft cambie sus tokens de clave pública en versiones posteriores del framework son escasas, aunque podría suceder. –

0

Usted puede ser capaz de salir adelante, marcando el nombre completo del tipo o el conjunto de la siguiente manera,

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

La forma más fácil Seguí es verificar el espacio de nombres de averiguar si es una de sus tipos personalizados Por ejemplo, su espacio de nombre podría ser "YourCompany.YourDepartment" y esto puede verificarse contra el espacio de nombres del tipo.

Cuestiones relacionadas