C# .Net 4-在程序集中包含自定义信息

C# .Net 4-在程序集中包含自定义信息,c#,.net,assemblies,C#,.net,Assemblies,我正在构建一个可扩展的应用程序,它将在运行时通过Assembly.LoadFile()加载其他程序集。这些附加程序集将包含WPF资源字典(皮肤等)、普通资源(Resx)和/或插件类等内容。程序集也不能包含公共类,只能包含资源或资源字典 我正在寻找一种识别程序集的方法,比如一个友好的名称(如“附加皮肤”或“集成浏览器”)、程序集的功能类型(SkinsLibrary、SkinsLibrary | PluginLibrary等)和附加信息(如ConflictsWith(新[]{“SkinsLibrar

我正在构建一个可扩展的应用程序,它将在运行时通过
Assembly.LoadFile()
加载其他程序集。这些附加程序集将包含WPF资源字典(皮肤等)、普通资源(Resx)和/或插件类等内容。程序集也不能包含公共类,只能包含资源或资源字典

我正在寻找一种识别程序集的方法,比如一个友好的名称(如“附加皮肤”或“集成浏览器”)、程序集的功能类型(SkinsLibrary、SkinsLibrary | PluginLibrary等)和附加信息(如ConflictsWith(新[]{“SkinsLibrary”、“BrowserPlugin”)

到目前为止,我在命名程序集(
*.Skins.*.dll
等)时使用了一种约定。在每个程序集中,我都有一个空的虚拟类,它只是保存实际(程序集范围)信息的自定义类属性的占位符,但这感觉像是一种黑客行为。是否有一些简化的标准方法来处理这个问题


我正在开发central loader系统,我团队中的其他开发人员将开发这些附加组件,因此我希望尽量减少约定和管道细节。

我得到了部分信息,但是


您可以通过访问链接添加您可以看到的内容。

对于插件,我对MvcTurbine有丰富的经验(它可以用于其他项目,而不仅仅是mvc)。如果您将它与Ninject结合使用,并为插件定义接口,即:

IPlugin{
    string Name {get;}
    someResultType PerformAction(someArgType arg);

}
并且,在插件dll中,通过从MvcTurbine实现IServiceRegistrator接口来注册IPlugin的实现,然后如果将带有插件的dll放入bin目录,插件实现将添加到列表中,该列表将被传递到使用DI的某个类的构造函数中并接收列表,或者您可以从IOC容器解析它手工 这比手工加载程序集并检查它们的接口/实现等要干净得多


如果您对此感兴趣,请询问是否有任何不清楚之处,我将详细说明。

编辑:我已用一些更详细的信息更新了答案。

下面是一个示例,说明如何完成您想做的事情。
首先为不同类型的插件类型定义一个枚举

public enum AssemblyPluginType
{
    Skins,
    Browser
}
添加两个用于描述插件的属性(程序集插件类型和潜在冲突)

现在,您可以将这些属性添加到程序集中

以下两行可以添加到程序集中的任何位置,只要它们位于命名空间之外。我通常将程序集属性放在
AssemblyInfo.cs
文件中,该文件可以在
Properties
文件夹中找到

[assembly: AssemblyPluginAttribute(AssemblyPluginType.Browser)]
[assembly: AssemblyPluginConflictAttribute(AssemblyPluginType.Skins, AssemblyPluginType.Browser)]
现在,您可以使用以下代码检查程序集的特定属性:

using System;
using System.Reflection;

namespace ConsoleApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Get the assembly we're going to check for attributes.
            // You will want to load the assemblies you want to check at runtime.
            Assembly assembly = typeof(Program).Assembly;

            // Get all assembly plugin attributes that the assembly contains.
            object[] attributes = assembly.GetCustomAttributes(typeof(AssemblyPluginAttribute), false);
            if (attributes.Length == 1)
            {
                // Cast the attribute and get the assembly plugin type from it.
                var attribute = attributes[0] as AssemblyPluginAttribute;
                AssemblyPluginType pluginType = attribute.PluginType;
            }
        }
    }
}

您可以使用;它从.NET 4.5开始提供。

如果正确命名(name.lang.resx),则应自动为当前语言加载资源文件(如果您有“default”资源已定义。Framework为您提供此功能。为什么您需要手动加载资源?因为这些资源文件已编译成程序集,并且其中有许多。例如,我有程序集Skin1和Skin2,配置指示应用程序使用Skin1,因此应用程序不应自动加载这两个。但是,应用程序I don’我不知道Skin2的存在,因此用户可以选择它。有没有可能以某种接口(ISkin)的实现形式拥有皮肤,所以您在一个dll中编写自己的实现,并向该dll添加必要的资源?对于每个外观,您将有一个程序集,并且从中引用的该程序集所需的所有资源将自动加载。您只需担心两个外观不会使用同名的资源(通过将skinname添加到命名约定中很容易防止)。但这正是问题所在,我希望尽量减少工作量(以及可能的运行时错误)对于其他开发人员。让他们为简单的资源字典程序集提供虚拟实现并引用某些特定于应用程序的DI框架是我想要避免的。如果您想最小化错误,那么您应该使用接口。实际上,您应该使用接口作为规范的一部分(或作为规范:)无论何时,只要您需要有人来制作一些功能。visual studio可以提供带有占位符的接口的自动实现,因此这也是工作的最小化。如果您不想使用任何DI框架,您可能想看看谢谢,这可能正是我要找的,我会尝试一下。谢谢,您可以指定吗我应该将这些
[assembly:…]
属性放在哪里,以及如何查询程序集中的这些属性?@Boris:我已经更新了答案,提供了更多关于在何处声明程序集属性以及如何从程序集查询信息的信息。
using System;
using System.Reflection;

namespace ConsoleApplication
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Get the assembly we're going to check for attributes.
            // You will want to load the assemblies you want to check at runtime.
            Assembly assembly = typeof(Program).Assembly;

            // Get all assembly plugin attributes that the assembly contains.
            object[] attributes = assembly.GetCustomAttributes(typeof(AssemblyPluginAttribute), false);
            if (attributes.Length == 1)
            {
                // Cast the attribute and get the assembly plugin type from it.
                var attribute = attributes[0] as AssemblyPluginAttribute;
                AssemblyPluginType pluginType = attribute.PluginType;
            }
        }
    }
}