无法通过程序集的自定义属性获取类型 [英] Cannot get types by custom attributes across assemblies

查看:43
本文介绍了无法通过程序集的自定义属性获取类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我的应用程序中创建一个基本的窗口小部件插件系统,并且目前处于一个棘手的地方,使用我的 WidgetAttribute 属性类(编译到exe中)的内置窗口小部件可以正常工作,但我似乎无法在我编写的任何测试插件中找到任何小部件.

i am attempting to create a basic widget plugin system within my app and i am currently at a sticking point where built in widgets that use my WidgetAttribute attribute class (compiled into the exe) work fine, but i cant seem to find any widgets in any of the test plugins i have written.

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

i am using the following code to load the assemblies:

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

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

and then the following code to get all types that have my attribute that denotes a widget and its meta data:

    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返回了一个空数组.

When i call the LoadAllWidgets for the second time (ie. loading the widgets that come from other assemblies), i get the type within the type array, but then GetCustomAttributes returns an empty array.

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

The attribute is defined as follows, and the same source file is used in both projects:

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;
    }
}
}

谁能告诉我为什么即使我已经加载了装配体并且可以看到该类型,但我仍无法从程序集外部的类型中获取自定义属性?

can anyone tell me why i cannot get custom attributes from a type outside of my assembly, even though i have loaded it and can see the type?

EDIT 另一个程序集中的插件类的定义如下:

EDIT a plugin class in the other assembly is defined as follows:

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

推荐答案

.Net中类型的标识为{程序集名称+类型名称}.

Identity of a type in .Net is {Assembly Name + type name}.

因此,由于使用的是两个项目中都使用了相同的源文件" ,这意味着在2个不同的程序集中有2个不同的属性(碰巧具有相同的名称).因此,ether程序集将无法轻松查看其他程序集的属性(两者都将看到属性,仅进行比较将无法按照您想要的方式进行.)

So since you are using "the same source file is used in both projects" that means there 2 different attributes in 2 different assemblies (which happen to have the same name). So ether assembly will not be able to see attributes from another assembly easily (both will see attributes, just comparing will not work the way you want).

解决方案:

  • 确保每个共享属性仅编译到一个程序集中,并且该程序集供该属性的所有使用者使用.
  • 比较属性名称,而不是类型.

相同的考虑因素适用于使用类型标识的其他情况.IE.如果接口在2个程序集之间作为源副本共享,则这些接口和实现它们的类将不兼容.

The same consideration applies for other cases when type identity is used. I.e. if interface is shared between 2 assemblies as source copy than these interface and classes that implement them will not be considered compatible.

通常,程序和相关程序集中的所有共享共享类型/接口/枚举都一起放在共享程序集中.这种程序集也可以视为公共API,并可以与旨在与您的程序集成的外部组件共享.

So often all shared shared types/interfaces/enumeration for program and related assemblies in are places into shared assembly together. Such assembly can also be considered public API and shared with external components that are designed to integrate with your program.

请注意,与他人共享程序集后,这意味着您需要版本控制故事,因为对共享程序集所做的许多更改(即,重命名类型/方法)都将导致从属程序集无法加载或发生故障.

Note that as soon as you share assembly with someone else it means you need versioning story as many changes (i.e. renaming of a type/method) to shared assembly will cause dependent assemblies to fail to load or malfunction.

这篇关于无法通过程序集的自定义属性获取类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆