2015-03-09 16 views
7

Ci sono alcune altre domande riguardo a questo su SO, ma ho sentito nessuno di loro ha davvero fornito una risposta solida.Perché i miei tipi non sono contrassegnati come uguali?

Ultimamente sto riflettendo molto con la riflessione e volevo controllare i tipi contenuti in alcuni assembly che implementano una determinata interfaccia.

quindi ho una classe chiamata BESCollector che implementa ICollector

public class BESCollector : ICollector 
{ 
    // ... 
} 

Qui ho caricare l'assembly, ciclo attraverso tutti i tipi e vedere se questo tipo contiene un'interfaccia di tipo ICollector ...

Assembly pluginAssembly = Assembly.ReflectionOnlyLoadFrom(pluginConfig.AssemblyLocation); 
IEnumerable<Type> types = pluginAssembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(ICollector))); 

... che non produce risultati :(Durante il debug, posso vedere chiaramente che esso contiene questo tipo. Mi interrompo sull'i-loop

Assembly pluginAssembly = Assembly.ReflectionOnlyLoadFrom(pluginConfig.AssemblyLocation); 
IEnumerable<Type> types = pluginAssembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(ICollector))); 
foreach (Type type in pluginAssembly.GetTypes()) 
{ 
    Type[] interfaces = type.GetInterfaces(); 
    if (interfaces.Contains(typeof(ICollector))) 
    { 
     Console.WriteLine(@"\o/"); 
    } 
} 

Questi risultati sono direttamente dal debugger. Qui si può vedere che interfaces contiene un unico tipo, vale a dire ICollector:

-  interfaces {System.Type[1]} System.Type[] 
    +  [0] {Name = "ICollector" FullName = "SquidReports.DataCollector.Interface.ICollector"} System.Type {System.ReflectionOnlyType} 

e il tipo sto chiamando .GetInterfaces() su è chiaramente BESCollector:

+  type {Name = "BESCollector" FullName = "SquidReports.DataCollector.Plugin.BES.BESCollector"} System.Type {System.ReflectionOnlyType} 

Ma l'affermazione dell'uguaglianza interfaces.Contains(typeof(ICollector)) mai restituisce true .

Solo così pensi che non sto mescolando i tipi qui, quando eseguo il mouse su (typeof(ICollector)) durante il debug, visualizza chiaramente SquidReports.DataCollector.Interface.ICollector.

Questo, naturalmente, funziona:

Type[] interfaces = type.GetInterfaces(); 
if (interfaces.Any(t => t.Name == typeof(ICollector).Name)) 
{ 
    Console.WriteLine(@"\o/"); 
} 

Ma che does't dimmi un bel po ', oltre al fatto che i tipi con lo stesso nome.

Inoltre, perché questo controllo fallisce?

if (typeof(ICollector).Equals(typeof(ICollector))) 
{ 
    Console.WriteLine("EQUALIZED"); 
} 

Perché il primo controllo di uguaglianza non riesce? Più specificamente, come funziona l'uguaglianza di tipo in C# 5.0? Non è stato implementato nulla di specifico per .Equals() per il tipo "Tipo"?

EDIT:

Su richiesta di I Qualità Catalyst seguito rapidamente ha fatto un test, se l'uguaglianza sarebbe valutato come vero se l'interfaccia e la classe sono stati definiti nello stesso assembly. Questo funziona:

class Program 
{ 
    public interface ITest 
    { 

    } 

    public class Test : ITest 
    { 
     public int ID { get; set; } 
    } 

    static void Main(string[] args) 
    { 
     Type[] interfaces = (typeof(Test)).GetInterfaces(); 
     if (interfaces.Any(t => t == typeof(ITest))) 
     { 
      Console.WriteLine(@"\o/"); 
     } 
    } 
} 

EDIT2: Ecco l'implementazione di ICollector

public interface ICollector 
{ 
    IDbRelay DbRelay { get; set; } 
    ILogManager LogManager { get; set; } 

    void Init(ILogManager logManager, IDbRelay dbRelay); 
    void Execute(); 
} 

Tuttavia, credo forse ho perso su un dettaglio importante.Sto lavorando con tre Assemblee qui:

  1. 'PRINCIPALE' (SquidReports.DataCollector) assemblaggio dove sto facendo il controllo di uguaglianza
  2. L' 'interfaccia' (SquidReports.DataCollector.Interface) assembly che contiene ICollector
  3. Il ' Plugin' (SquidReports.DataCollector.Plugin.BES) assembly che contiene la definizione di BESCollector

probabilmente è molto importante notare che il 'Interface' (SquidReports.DataCollector.Interface) viene caricata dall'evento ReflectionOnlyAssemblyResolve, come mostrato di seguito, perché ReflectionOnlyLoadFrom() non risolve automaticamente le dipendenze:

public Assembly ReflectionOnlyAssemblyResolve(object sender, ResolveEventArgs args) 
{ 
    // This event is used to resolve dependency problems. We need to return the requested assembly in this method. 
    // We should probably look in two locations: 
    // 1. The SquidReports.DataCollector folder 
    // 2. The Corresponding folder in SquidReports.DataCollector\Plugins  

    // Let's first turn the 'full' assembly name into something more compact 
    AssemblyName assemblyName = new AssemblyName(args.Name); 
    this.Logger.LogMessage(LogLevel.Debug, String.Format("Attempting to resolve Assembly {0} to load {0}", assemblyName.Name, args.RequestingAssembly.GetName().Name)); 

    // Let's also get the location where the requesting assembly is located 
    DirectoryInfo pluginDirectory = Directory.GetParent(args.RequestingAssembly.Location); 
    string assemblyFileName = String.Format("{0}.dll", assemblyName.Name); 

    if (File.Exists(assemblyFileName)) 
    { 
     // It's in the main bin folder, let's try to load from here 
     return Assembly.ReflectionOnlyLoadFrom(assemblyFileName); 
    } 
    else if (File.Exists(Path.Combine(pluginDirectory.FullName, assemblyFileName))) 
    { 
     // It's in the plugin folder, let's load from there 
     return Assembly.ReflectionOnlyLoadFrom(Path.Combine(pluginDirectory.FullName, assemblyFileName)); 
    } 

    return null; 
} 

Edit3: Su suggerimento di Joe di seguito, ho il debug l'applicazione di nuovo di utilizzare questo:

if (type.Name == "BESCollector") 
{ 
    Type[] interfaces = type.GetInterfaces(); 
    Type interface1 = interfaces[0]; 
    Type interface2 = typeof(ICollector); 
    Console.WriteLine(""); 
} 

Ho copiato il completa le proprietà di interface1 e interface2, quindi le ha lanciate in un file diff.

Il risultato, credo, potrebbe essere risolto il mio problema:

interface1 è descritto come segue:

interface1 {Name = "ICollector" FullName = "SquidReports.DataCollector.Interface.ICollector"} System.Type {System.ReflectionOnlyType} 

Mentre interface2 è descritto in questo modo:

interface2 {Name = "ICollector" FullName = "SquidReports.DataCollector.Interface.ICollector"} System.Type {System.RuntimeType} 

Così sono io corretto assumendo che il problema sia causato perché {System.RuntimeType}! = {System.ReflectionOnlyType}, e che Assembly.ReflectionOnlyLoadFrom() è per b zoppo per questo?

+0

Il controllo di uguaglianza funziona con qualsiasi altra interfaccia definita nello stesso assembly? –

+0

@Catalyst qualità: in realtà sembra funzionare, vedere il mio aggiornamento sopra. Non seguo abbastanza qui. –

+0

Puoi anche mostrarci la dichiarazione di "ICollector" per favore? –

risposta

2

sono incappato le risposte grazie a Joe Enzminger:

Sembrerebbe che, in quanto stavo usando Assembly.ReflectionOnlyLoadFrom(), il tipo che mi stava caricando dall'Assemblea era in realtà uno System.ReflectionOnlyType al contrario di un sistema. RuntimeType.

In sostanza, c'è una semplice e una soluzione piuttosto fresco per questo:

  1. Smettere di usare ReflectionOnlyLoadFrom() e passare a LoadFrom(). Questo risolve tutti i tuoi problemi. A meno che non si stia utilizzando ReflectionOnlyLoadFrom per un'ottima ragione.
  2. In tal caso, è sufficiente utilizzare Type.GUID. Indipendentemente dal contesto da cui è stato caricato il tipo, i GUID saranno gli stessi. Così si può fare semplice

    if ((typeof (MyReflectionType)). GUID == (typeof (MyType)). GUID) {// Blah ...}

Questo dovrebbe risolvi i tuoi problemi :)

+0

Buona idea per confrontare i GUID. –

Problemi correlati