2010-07-04 11 views

Respuesta

7

La única manera segura compruebe si un tipo es parte de un ensamblaje para verificar el nombre completo del ensamblado que contiene su nombre, versión, cultura y clave pública (si está firmado). Todas las bibliotecas de clase base .Net (BCL) están firmadas por microsoft usando sus claves privadas. Esto hace que sea casi imposible para cualquier otra persona crear un ensamblado con el mismo nombre totalmente calificado que una biblioteca de clase base.

//add more .Net BCL names as necessary 
var systemNames = new HashSet<string> 
{ 
"mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", 
"System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
}; 

var isSystemType = systemNames.Contains(objToTest.GetType().Assembly.FullName); 

una solución ligeramente menos frágil es el uso de la clase AssemblyName y omitir la comprobación de número de versión/cultura. Por supuesto, esto supone que la clave pública no cambia entre las versiones.

//add more .Net BCL names as necessary 
var systemNames = new List<AssemblyName> 
{ 
new AssemblyName ("mscorlib, Version=4.0.0.0, Culture=neutral, " + 
        "PublicKeyToken=b77a5c561934e089"), 
new AssemblyName ("System.Core, Version=4.0.0.0, Culture=neutral, "+ 
        "PublicKeyToken=b77a5c561934e089") 
}; 

var obj = GetObjectToTest(); 

var objAN = new AssemblyName(obj.GetType().Assembly.FullName); 

bool isSystemType = systemNames.Any(
     n => n.Name == objAN.Name 
      && n.GetPublicKeyToken().SequenceEqual(objAN.GetPublicKeyToken())); 

La mayor parte del BCL se ha firmado con la misma clave, pero no con todas. Puede usar la clase AssemblyName para simplemente verificar el token de clave pública. Depende de tus necesidades.

4

Puede verificar el conjunto en el que se ha declarado el tipo.

object.GetType().Assembly 
+3

Entonces, la pregunta es: ¿cómo saber que un ensamblado es parte del framework .NET? –

5

Si simplemente desea distinguir entre MyClass y string entonces usted puede comprobar para esos tipos directa:

Type typeToTest = GetTypeFromSomewhere(); 

if (typeToTest == typeof(MyClass)) 
    MyClassAction(); 
else if (typeToTest == typeof(string)) 
    StringAction(); 
else 
    NotMyClassOrString(); 

Si necesita una comprobación más general de si es o no un determinado tipo es un marco escribe a continuación, se puede comprobar si pertenece al espacio de nombres System:

// create an array of the various public key tokens used by system assemblies 
byte[][] systemTokens = 
    { 
     typeof(System.Object) 
      .Assembly.GetName().GetPublicKeyToken(), // B7 7A 5C 56 19 34 E0 89 
     typeof(System.Web.HttpRequest) 
      .Assembly.GetName().GetPublicKeyToken(), // B0 3F 5F 7F 11 D5 0A 3A 
     typeof(System.Workflow.Runtime.WorkflowStatus) 
      .Assembly.GetName().GetPublicKeyToken() // 31 BF 38 56 AD 36 4E 35 
    }; 

Type typeToTest = GetTypeFromSomewhere(); 

string ns = typeToTest.Namespace; 
byte[] token = typeToTest.Assembly.GetName().GetPublicKeyToken(); 

bool isSystemType = ((ns == "System") || ns.StartsWith("System.")) 
        && systemTokens.Any(t => t.SequenceEqual(token)); 
+0

No es realmente a prueba de balas, por ejemplo si el espacio de nombres se llama "SystemUtil";) –

+0

@thomas: Me di cuenta de que poco después de publicar pero me llamaron antes de poder editar. Ahora arreglado. – LukeH

+0

Estoy bastante seguro de que realmente puede escribir su propio ensamblaje y hacer el espacio de nombres 'System. [Something]' ... No soy un gran fanático de hacer esto, pero sé que algunos proyectos de código abierto lo hacen, por ejemplo , ['System.Data.SQLite'] (http://sqlite.phxsoftware.com/), [' System.Drawing.Html'] (http://htmlrenderer.codeplex.com/). –

0

No todas las clases comienzan en el marco Sys tem namespace (también pueden ser Microsoft, etc.).

Como tal, que probablemente se podría comparar la ubicación de una clase conocida marco con la del tipo que se está probando como:

if (String.CompareOrdinal(
     Path.GetDirectoryName(typeof(String).Assembly.Location), 
     Path.GetDirectoryName(typeof(MyType).Assembly.Location) 
    ) == 0) 
    { 
    //Framework Type 
    } 
    else 
    { 
    //3rd Party DLL 
    } 

No es la mejor solución; pero más seguro que solo probar si el espacio de nombres comienza con el sistema (podría crear un espacio de nombres que comience con un sistema que no sea una clase de infraestructura).

Editar

también, además de la prueba anterior, no estaría de más para verificar que el tipo se carga desde el caché de ensamblados global:

typeof(MyType).Assembly.GlobalAssemblyCache 
+2

Que yo sepa, el BCL consiste solamente en los espacios de nombres 'System. *'. Los espacios de nombres 'Microsoft. *' Son un superconjunto del BCL - a veces conocido como FCL - y no son parte del estándar ECMA CLI. http://en.wikipedia.org/wiki/Base_Class_Library – LukeH

+0

@LukeH: Realmente es un buen punto. El punto importante que estaba buscando era no confiar en el espacio de nombres que comenzaba con el Sistema. Y como otras soluciones han demostrado, ser explicto siempre es la mejor opción; este es un cheque de "hombre pobre" que pensé que vomitaría por las dudas. –

1

Comprobar si el conjunto pertenece a la biblioteca CLR:

myType.Module.ScopeName == "CommonLanguageRuntimeLibrary" 

como se explica here.

Cuestiones relacionadas