实现接口和匹配属性的MEF加载类型

时间:2014-05-13 11:12:19

标签: c# .net reflection mef

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

我使用[FileType(" .jpg")]

在JPEGLoader中实现IFileLoader

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

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。

1 个答案:

答案 0 :(得分:2)

使用MEF和attachnig Metadata可以获得所需的文件加载器。

创建元数据界面和属性。

public interface IFileTypeMetadata
{
    string FileExtension { get; }
} 

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

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

FileTypeAttribute类实现IFileTypeMetadata接口,您可以向setter属性添加FileExtension。实现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"