2015-03-09 6 views
7

Es gibt ein paar andere Fragen dazu auf SO, aber ich fühlte, dass keiner von ihnen wirklich eine solide Antwort lieferte.Warum werden meine Typen nicht als gleich gekennzeichnet?

Ich bin in letzter Zeit viel mit Reflektion herumalbern, und ich wollte nach Typen innerhalb einiger Assemblys suchen, die eine bestimmte Schnittstelle implementieren.

So habe ich eine Klasse namens BESCollector die ICollector implementiert

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

Hier lade ich die Montage, eine Schleife durch alle Arten und sehen, ob diese Art eine Schnittstelle vom Typ ICollector enthält ...

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

..., die keine Ergebnisse :(ergibt. Während das Debuggen ich deutlich sehen, dass es diese Art enthält. ich breche auf dem if-Schleife

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/"); 
    } 
} 

Diese Ergebnisse stammen direkt vom Debugger. Hier können Sie sehen, dass interfaces einen einzigen Typ enthält, nämlich ICollector:

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

Und die Typ-I-Aufruf bin .GetInterfaces() auf deutlich BESCollector:

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

Aber die Gleichheit Aussage interfaces.Contains(typeof(ICollector)) wertet nie wahr .

Nur damit Sie denken, ich bin nicht Typen hier zu vermischen, wenn ich Maus über (typeof(ICollector)) während des Debuggens, zeigt es deutlich SquidReports.DataCollector.Interface.ICollector.

Dies ist natürlich funktioniert:

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

Aber die does't mir eine ganze Menge sagen, außer der Tatsache, dass die Typen mit dem gleichen Namen.

Außerdem, warum schlägt diese Überprüfung fehl?

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

Warum schlägt meine erste Gleichheitsprüfung fehl? Genauer gesagt, wie funktioniert Typgleichheit in C# 5.0? Wurde für .Equals() für den Typ "Type" nichts spezifisch implementiert?

EDIT:

Auf Wunsch von I Qualität Katalysator unten schnell einen Test hat, wenn die Gleichheit zu wahren bewerten würde, wenn die Schnittstelle und Klasse in der gleichen Baugruppe definiert wurden. Das funktioniert:

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: Hier ist die Implementierung von ICollector

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

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

Aber ich glaube, ich habe auf ein wichtiges Detail kann verpasst.Ich arbeite mit drei Baugruppen hier:

  1. Die 'Main' (SquidReports.DataCollector) Montage, wo ich die Gleichheitsprüfung
  2. Die 'Schnittstelle' mache (SquidReports.DataCollector.Interface) Assembly, enthält ICollector
  3. Die ' Plugin' (SquidReports.DataCollector.Plugin.BES) Assembly, die die Definition von BESCollector enthält

Es ist wahrscheinlich sehr wichtig zu beachten, dass die ‚Schnittstelle‘ (SquidReports.DataCollector.Interface) wird aus dem Ereignis ReflectionOnlyAssemblyResolve geladen, wie unten gezeigt, weil ReflectionOnlyLoadFrom() nicht automatisch Abhängigkeiten löst:

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: unten Auf Anregung von Joe, ich gedebuggt die Anwendung erneut diese mit:

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

ich die kopierte vollständige Eigenschaften von interface1 und interface2, dann warf diese in eine Datei diff.

Das Ergebnis, glaube ich, haben mein Problem gelöst:

interface1 wird wie folgt beschrieben:

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

Während interface2 wird wie folgt beschrieben:

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

ich so bin Korrekte Annahme, dass das Problem verursacht wird, weil {System.RuntimeType}! = {System.ReflectionOnlyType} und das Assembly.ReflectionOnlyLoadFrom() zu b ist lahm dafür?

+0

Funktioniert Ihre Gleichheitsprüfung mit irgendeiner anderen Schnittstelle, die in der gleichen Versammlung definiert wird? –

+0

@Quality Catalyst: Nun, eigentlich scheint das zu funktionieren, siehe mein Update oben. Ich folge hier nicht ganz. –

+0

Können Sie uns bitte auch die Erklärung von 'ICollector 'zeigen? –

Antwort

2

Ich stolperte über die Antwort dank Joe Enzminger:

Es dass erscheinen würde, weil ich Assembly.ReflectionOnlyLoadFrom() verwendet wurde, die Art, die ich von der Versammlung geladen wurde, war eigentlich ein System.ReflectionOnlyType als Gegensatz zu einem System. Laufzeittyp

Im Grunde ist es eine einfache und eine ziemlich coole Lösung für dieses:

  1. Stopp ReflectionOnlyLoadFrom() mit und wechseln Sie in Loadfrom(). Dies löst alle Ihre Probleme. Es sei denn, Sie verwenden ReflectionOnlyLoadFrom aus einem sehr guten Grund.
  2. In diesem Fall können Sie einfach Type.GUID verwenden. Unabhängig vom Kontext, aus dem der Typ geladen wurde, sind die GUIDs identisch. So einfach, dass man

    tun können

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

Das sollte lösen Sie Ihre Probleme :)

+0

Gute Idee GUIDs zu vergleichen. –

Verwandte Themen