无法跨程序集通过自定义属性获取类型

时间:2013-06-20 22:44:26

标签: c# .net reflection

我正在尝试在我的应用程序中创建一个基本的小部件插件系统,我目前处于一个棘手的问题,内置使用我的WidgetAttribute属性类(编译到exe)的小部件工作正常,但我不能似乎在我编写的任何测试插件中都找到了任何小部件。

我使用以下代码加载程序集:

    public static void LoadAll()
    {
        String[] m_filenames = Directory.GetFiles("plugins", "*.dll", SearchOption.TopDirectoryOnly);
        foreach (String fn in m_filenames)
        {
            Load(Directory.GetCurrentDirectory() + "\\" + fn);
        }
    }

    public static void Load(String filename)
    {
        Assembly m_asm = Assembly.Load(File.ReadAllBytes(filename));
        PluginAssemblies.Add(m_asm);
    }

然后使用以下代码获取具有表示窗口小部件及其元数据的属性的所有类型:

    public static void LoadAllWidgets()
    {
        foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            LoadAllWidgets(assembly);
        }

        foreach (Assembly assembly in PluginLoader.PluginAssemblies)
        {
            LoadAllWidgets(assembly);
        }
    }

    public static void LoadAllWidgets(Assembly asm)
    {
        foreach (Type type in asm.GetTypes())
        {
            WidgetAttribute[] m_attribs = (WidgetAttribute[])type.GetCustomAttributes(false).OfType<WidgetAttribute>().ToArray();
            if (m_attribs.Length > 0)
            {
                WidgetsByGuid.Add(m_attribs[0].ID, type);
                WidgetNamesByGuid.Add(m_attribs[0].ID, m_attribs[0].Name);
                WidgetShowInMenuByGuid.Add(m_attribs[0].ID, m_attribs[0].ShowInMenu);
            }
        }
    }

当我第二次调用LoadAllWidgets时(即加载来自其他程序集的小部件),我得到类型数组中的类型,但GetCustomAttributes返回一个空数组。

该属性定义如下,两个项目中使用相同的源文件:

using System;
using System.Reflection; 

namespace WSW.Classes
{
[AttributeUsage(AttributeTargets.Class)]
public class WidgetAttribute : System.Attribute
{
    public String Name { get; set; }
    public Guid ID { get; set; }
    public Boolean ShowInMenu { get; set; }

    public WidgetAttribute(String guid, String name, Boolean showmenu)
    {
        Name = name;
        ID = Guid.Parse(guid);
        ShowInMenu = showmenu;
    }

    public WidgetAttribute(String guid, String name)
    {
        Name = name;
        ID = Guid.Parse(guid);
        ShowInMenu = true;
    }
}
}

任何人都可以告诉我为什么我不能从我的程序集之外的类型获取自定义属性,即使我已经加载它并且可以看到类型?

编辑其他程序集中的插件类定义如下:

[WSW.Classes.WidgetAttribute("{42544B13-7353-40FD-B1D8-DA46A247110A}", "Testimonials")]
public partial class Testimonials : UserControl
{
    public Testimonials()
    {
        InitializeComponent();
    }
}

1 个答案:

答案 0 :(得分:1)

.Net中的类型标识是{Assembly Name + type name}。

因此,由于您正在使用“两个项目中使用相同的源文件”,这意味着2个不同的程序集中有2个不同的属性(恰好具有相同的名称)。所以以太组装将无法轻易地看到来自另一个组件的属性(两者都会看到属性,只是比较不会按照你想要的方式工作)。

解决方案:

  • 确保每个共享属性仅编译为一个程序集和该属性的所有使用者使用的程序集。
  • 比较属性的名称,而不是类型。

同样的考虑适用于使用类型标识的其他情况。即如果两个程序集之间的接口作为源副本共享而不是这些接口,则实现它们的类将不被视为兼容。

因此,程序和相关程序集中的所有共享共享类型/接口/枚举通常都会共享到共享程序集中。此类程序集也可以被视为公共API,并与旨在与您的程序集成的外部组件共享。

请注意,只要您与其他人共享程序集,就意味着您需要版本控制故事,因为许多更改(即重命名类型/方法)到共享程序集将导致依赖程序集无法加载或出现故障。