【问题标题】:MEF load types that implement interface and match attributes实现接口和匹配属性的 MEF 加载类型
【发布时间】:2014-05-13 11:12:19
【问题描述】:

假设我有一个接口 IFileLoader 和属性 FileTypeAttribute

我在 JPEGLoader 中使用 [FileType(".jpg")] 实现 IFileLoader

我可以使用 MEF 加载实现 IFileLoader 并匹配 .jpg 作为文件扩展名的类(JPEGLoader),以便我可以实现以下方法:

public void IFileLoader GetLoader(string filename);

这可以用 MEF 完成,还是我应该坚持这个:

var allTypes = assemblies.SelectMany(a => a.GetTypes());
var classes = allTypes.Where(t => t.IsClass && ! t.IsAbstract);
var fileLoaders = classes.where(t => typeof(IFileLoader).IsAssignableFrom(t));
var forType = fileLoaders.Where(t => t.GetAtributeValue<FileTypeAttribute,string>(t => t.FileType, string.Empty) == fileType);
var loaderInstances = fileLoaders.Select(t => Activator.CreateInstance(t) as IFileLoader);

或者上述至少变成了 ILookup,或者可能是我没有考虑过的其他东西?

我希望能够在项目的不同程序集中甚至在插件程序集中实现 IFileLoader。

【问题讨论】:

    标签: c# .net reflection mef


    【解决方案1】:

    可以通过使用MEF和将Metadata附加到导出的部分来获取您需要的文件加载器。

    创建元数据接口和属性。

    public interface IFileTypeMetadata
    {
        string FileExtension { get; }
    } 
    

    界面可以包含您需要的任意数量的属性。对于这个特殊问题,它只包含一个属性FileExtension。重要的是该属性只有getterMEF 旨在不允许在运行时更改元数据。然后创建保存元数据的属性:

    public class FileTypeAttribute : Attribute, IFileTypeMetadata    
    {        
        public string FileExtension { get; set; }
    }
    

    FileTypeAttribute 类实现了IFileTypeMetadata 接口,您可以在FileExtension 属性中添加setter。它是实现FileLoader 类所必需的,MEF 不会抱怨,因为我们将通过IFileTypeMetadata 接口访问元数据,其中包含只有getters 的属性

    创建文件加载器类实现的接口和文件加载器类。

    public interface IFileLoader
    {
        string LoadFile();
    }
    

    为简单起见,该接口仅包含一种方法。下面是两个不同的虚拟文件加载器类的示例:

    [Export(typeof(IFileLoader))]
    [FileType(FileExtension = ".jpg")]
    public class JpgFileLoader : IFileLoader
    {
        public string LoadFile()
        {
            return "JPG"; 
        }
    }
    
    [Export(typeof(IFileLoader))]
    [FileType(FileExtension = ".png")]
    public class PngFileLoader : IFileLoader
    {
        public string LoadFile()
        {
            return "PNG";
        }
    }
    

    这两个类都实现了IFileLoader 接口并作为IFileLoader 部分导出,但它们通过FileType 属性具有不同的元数据。

    创建合成容器

    var catalog = new DirectoryCatalog("path to directory where dll's are located");
    var compositionContainer = new CompositionContainer(catalog);
    compositionContainer.ComposeParts();
    

    访问导出的部分

    var fileLoaders = compositionContainer.GetExports<IFileLoader, IFileTypeMetadata>();
    
    var jpgFileLoader = fileLoaders.FirstOrDefault(x => x.Metadata.FileExtension == ".jpg");
    
    if (jpgFileLoader != null)
        Console.WriteLine(jpgFileLoader.Value.LoadFile()); //should print "JPG"
    
    var pngFileLoader = fileLoaders.FirstOrDefault(x => x.Metadata.FileExtension == ".png");
    
    if (pngFileLoader != null)
        Console.WriteLine(pngFileLoader.Value.LoadFile()); //should print "PNG"
    

    【讨论】:

      猜你喜欢
      • 2012-01-16
      • 2013-09-27
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 2012-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多