为什么我的类型没有标记为相同?

时间:2015-03-09 01:46:49

标签: c# reflection types interface

关于此问题还有其他一些问题,但我觉得其中没有一个真正提供了可靠的答案。

我最近在讨论很多事情,我想检查实现某个界面的几个程序集中包含的类型。

所以我有一个名为BESCollector的类,它实现了ICollector

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

这里我加载程序集,循环遍历所有类型,看看该类型是否包含ICollector类型的接口......

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

...没有结果:(。调试时我可以清楚地看到它包含这种类型。我打破了if-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/");
    }
}

这些结果直接来自调试器。在这里你可以看到interfaces包含一个Type,即ICollector:

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

而且我打电话.GetInterfaces()的类型I显然是BESCollector:

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

但是,等式语句interfaces.Contains(typeof(ICollector))永远不会评估为真。

因此您认为我没有在此处混合类型,当我在调试时将鼠标移到(typeof(ICollector))时,它会清楚地显示SquidReports.DataCollector.Interface.ICollector

当然,这确实有效:

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

但除了同名的类型之外,这并不能告诉我很多。

此外,为什么这次检查失败?

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

为什么我的第一次检查失败?更具体地说,类型相等如何在C#5.0中起作用?是否有针对&#39; Type&#39;的.Equals()实现的具体内容。类型?

修改

如果接口和类在同一个程序集中定义,则在下面的I质量催化器的请求下,如果等式将评估为true,则快速进行测试。这项工作:

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 :这里是ICollector的实现

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

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

但是,我相信我可能错过了一个重要的细节。我在这里使用三个程序集:

  1. &#39; Main&#39; (SquidReports.DataCollector)汇编,我正在进行相等检查
  2. &#39;接口&#39; (SquidReports.DataCollector.Interface)包含ICollector的程序集
  3. &#39;插件&#39; (SquidReports.DataCollector.Plugin.BES)包含BESCollector定义的程序集
  4. 注意“界面”可能非常重要。 (SquidReports.DataCollector.Interface)正在从ReflectionOnlyAssemblyResolve事件加载,如下所示,因为ReflectionOnlyLoadFrom()不会自动解析依赖项:

    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 :根据Joe的建议,我使用以下方法再次调试了应用程序:

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

    我复制了interface1interface2的完整属性,然后将它们放在文件差异中。

    我认为结果可能解决了我的问题:

    interface1描述如下:

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

    interface2的描述如下:

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

    所以我认为问题是由{System.RuntimeType}!= {System.ReflectionOnlyType}引起的,而Assembly.ReflectionOnlyLoadFrom()应该归咎于此吗?

1 个答案:

答案 0 :(得分:3)

感谢Joe Enzminger,我偶然发现了答案:

看起来,因为我使用Assembly.ReflectionOnlyLoadFrom(),我从Assembly加载的Type实际上是System.ReflectionOnlyType而不是System.RuntimeType。

基本上,有一个简单而且非常酷的解决方案:

  1. 停止使用ReflectionOnlyLoadFrom()并切换到LoadFrom()。这解决了所有问题。当然,除非你出于很好的理由使用ReflectionOnlyLoadFrom。
  2. 在这种情况下,您只需使用Type.GUID即可。无论加载类型的上下文如何,GUID都是相同的。所以你可以简单地做到

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

  3. 这应该可以解决你的问题:)