2010-07-04 12 views

risposta

7

L'unico modo per sicurezza controllare se un tipo fa parte di un assembly è controllare il nome completo dell'assembly che contiene il suo nome, versione, cultura e chiave pubblica (se firmato). Tutte le librerie di classi di base .Net (BCL) sono firmate da Microsoft utilizzando le loro chiavi private. Ciò rende quasi impossibile per chiunque altro creare un assembly con lo stesso nome completo di una libreria di classi 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 soluzione leggermente meno fragile è utilizzare la classe AssemblyName e ignorare il controllo versione/cultura. Questo ovviamente presuppone che la chiave pubblica non cambi tra le versioni.

//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 maggior parte dei BCL è stata firmata con la stessa chiave ma non tutti. È possibile utilizzare la classe AssemblyName per controllare semplicemente il token della chiave pubblica. Dipende dai tuoi bisogni.

4

È possibile controllare l'assemblea in cui viene dichiarato il tipo.

object.GetType().Assembly 
+3

Quindi la domanda è: come sapere che un assembly fa parte del framework .NET? –

5

Se si vuole semplicemente distinguere tra MyClass e string quindi è possibile verificare la presenza di questi tipi direttamente:

Type typeToTest = GetTypeFromSomewhere(); 

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

Se avete bisogno di un controllo più generale o meno di un determinato tipo è un quadro digita allora si potrebbe verificare se appartiene alla System namespace:

// 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

Non proprio a prova di proiettile, per esempio se lo spazio dei nomi è chiamato "SystemUtil";) –

+0

@thomas: l'ho capito subito dopo la pubblicazione ma è stato chiamato via prima che potessi modificare. Ora risolto. – LukeH

+0

Sono abbastanza sicuro di poter scrivere il proprio assembly e creare il namespace 'System. [Qualcosa]' ... Non sono un grande fan di questo, ma so che alcuni progetti open-source fanno - ad es. , ['System.Data.SQLite'] (http://sqlite.phxsoftware.com/), [' System.Drawing.Html'] (http://htmlrenderer.codeplex.com/). –

0

Non tutte le classi del framework iniziare nel Sys spazio dei nomi tem (possono anche essere Microsoft ecc.).

Come tale, probabilmente si potrebbe confrontare la posizione di una nota di classe quadro con quello del tipo che si sta verificando come ad esempio:

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

Non la soluzione ottimale; ma più sicuro che testare solo se lo spazio dei nomi inizia con System (potrei creare uno spazio dei nomi che inizia con System che non è una classe framework).

Modifica

Inoltre, in aggiunta alla prova di cui sopra, non sarebbe male a verificare che il tipo viene caricato dalla Global Assembly Cache:

typeof(MyType).Assembly.GlobalAssemblyCache 
+2

Per quanto ne so, il BCL consiste solo degli spazi dei nomi 'System. *'. Gli spazi dei nomi 'Microsoft. *' Sono un superset del BCL - a volte noto come FCL - e non fanno parte dello standard ECMA CLI. http://en.wikipedia.org/wiki/Base_Class_Library – LukeH

+0

@LukeH: Davvero un buon punto. Il punto importante che stavo cercando era di non fare affidamento sul namespace che inizia con System. E come hanno dimostrato altre soluzioni, l'esplicazione è sempre la migliore scommessa; questo è un assegno di "pover'uomo" che pensavo di vomitare per ogni evenienza. –

1

Controllare se l'assemblea appartiene alla libreria CLR:

myType.Module.ScopeName == "CommonLanguageRuntimeLibrary" 

come spiegato here.

Problemi correlati