简体   繁体   English

属性,接口或抽象类

[英]Attribute, interface, or abstract class

I'm wondering what the general recommendation would be (attribute, interface, abstract class, or combination thereof) for the following implementation: 我想知道以下实现的一般建议(属性,接口,抽象类或其组合):

    /// <summary>
    /// Loads class specific information into a list for serialization. The class must extend PlugIn.
    /// The filenames parameter is passed from a FileDialog.
    /// </summary>
    /// <param name="filenames">Accepts any number of filenames with fully qualified paths.</param>
    public static void ExtractPlugInData(params string[] filenames)
    {
     List<Type> l;

     foreach (string f in filenames)
     {
     Assembly a = Assembly.LoadFrom(f);
     // lambda expression selects any class within a library extending the abstract PlugIn class
     l = a.GetTypes().Where(type => typeof(PlugIn).IsAssignableFrom(type)).ToList<Type>();

     if (l.Count > 0)
            //  write data to serializable class
      WritePlugInData(f , l);
     else
      // throw exception
      WriteLine("{0} :: No PlugIn Data Found" , a.FullName);
            }
    }

I realize there are advantages and disadvantages to each method. 我意识到每种方法都有优点和缺点。 Obviously, attributes require some reflection (as do abstract extension and interface implementation). 显然,属性需要一些反思(抽象扩展和接口实现也是如此)。 An abstract class takes our only base inheritance, and any future changes in an interface can break any existing plugins. 抽象类采用我们唯一的基本继承,接口中的任何未来更改都可以破坏任何现有插件。 So, as I see it, those are the disadvantages. 所以,正如我所看到的那样,这些都是缺点。

Performance is not an issue (unless there is something I don't see) since any reflection is only done once when a qualified class is extracted. 性能不是问题(除非有一些我看不到的东西)因为任何反射只在提取限定类时才进行一次。 The key pieces of data that are getting saved is a name for the plugin ("MyPlugIn"), the namespace ("SuperPlugIn.PlugInClass"), and the startup path for the .dll. 要保存的关键数据是插件的名称(“MyPlugIn”),命名空间(“SuperPlugIn.PlugInClass”)以及.dll的启动路径。 Right now, with the abstract PlugIn class, the extension of the properties is enforced. 现在,使用抽象的PlugIn类,强制执行属性的扩展。 This is more or less the same result if we implement an interface (IPlugIn). 如果我们实现接口(IPlugIn),这或多或少是相同的结果。

We are allowing custom plugins to be written by end-users. 我们允许最终用户编写自定义插件。 With the plugins we are writing in-house, it is easy to teach and enforce a required structure for our application to instance a qualified class. 使用我们内部编写的插件,可以很容易地为我们的应用程序教授和实施一个必需的结构来实例化一个合格的类。 However, I'm also considering the difficulties or inconvenience to the end-user should there be a major change. 但是,如果出现重大变化,我也在考虑最终用户的困难或不便。

All comments, suggestions, and questions welcome!! 欢迎所有评论,建议和问题!

Note: thanks go to Jon Skeet for the lambda expression in the snippet. 注意:感谢Jon Skeet在片段中的lambda表达式。 :) :)

EDIT: I should have noted in the beginning that this is intended to be platform independent (ie Mono). 编辑:我应该在开始时注意到这是平台无关的(即Mono)。

UPDATE: Based on the excellent recommendations, comments, and links below, a mix of attributes and interfaces is the best approach. 更新:基于下面的优秀建议,评论和链接,混合属性和接口是最好的方法。 Attributes let you load the assembly and check for required information and implementations rather safely without instancing the plugin classes/objects. 通过属性,您可以加载程序集并相当安全地检查所需的信息和实现,而无需实例化插件类/对象。 This is ideal in situations where 3rd party or end users are allowed to create custom plugins. 这在允许第三方或最终用户创建自定义插件的情况下非常理想。 We can check to ensure that the proper contract implementation is in place where the attribute says it's suppose to be. 我们可以检查以确保正确的合同实施到位,其中属性表示它是假设的。 We can check for required dependencies and resources and alert the developer of any problems before anything is instanced. 我们可以检查所需的依赖项和资源,并在实例化之前提醒开发人员任何问题。

You want your end users to write plugins? 您希望最终用户编写插件吗? I don't think that's a very good idea, unless your end users are programmers. 除非你的最终用户是程序员,否则我认为这不是一个好主意。

I'm going to keep my answer short this time since this is a pretty big honkin' dupe : 这次我会保持我的答案很短,因为这是一个相当 大的 honkin' 欺骗

Edit: For Mono, check out Mono.Addins . 编辑:对于Mono,请查看Mono.Addins

Assembly.GetTypes is a very expensive call, and I would avoid it where possible. Assembly.GetTypes是一个非常昂贵的调用,我会尽可能避免它。 (App startup time matters) (App启动时间很重要)

The faster way to do this is probably (I haven't benchmarked) an assembly-level attribute, which would be used like this: 更快的方法是(我没有基准测试)一个程序集级属性,可以像这样使用:

[assembly: PluginClass(typeof(MyPlugin), more info)]

You can then call GetCustomAttributes on the Assembly , which would probably be much faster than GetTypes . 然后,您可以在Assembly上调用GetCustomAttributes ,这可能比GetTypes快得多。

Using LINQ: 使用LINQ:

filenames.SelectMany(f => 
        Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute), true)
        .Cast<PluginClassAttribute>()
        .Select(a => a.PluginType)
).ToList();

I'd probably tend to use attributes. 我可能倾向于使用属性。 Extending the base class system with metadata is kind of exactly what they're for, and saying 'this class is a plugin' certainly fits that bill. 使用元数据扩展基类系统正是它们的目的,并且说“这个类是一个插件”当然适合这个法案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM