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

Sti*_*lon 7 .net c# reflection mef

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

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

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

public void IFileLoader GetLoader(string filename);
Run Code Online (Sandbox Code Playgroud)

可以用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);
Run Code Online (Sandbox Code Playgroud)

或者上面至少变成了ILookup,或者是其他我没想过的东西?

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

Ili*_*mov 2

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

创建元数据接口和属性。

public interface IFileTypeMetadata
{
    string FileExtension { get; }
} 
Run Code Online (Sandbox Code Playgroud)

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

public class FileTypeAttribute : Attribute, IFileTypeMetadata    
{        
    public string FileExtension { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

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

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

public interface IFileLoader
{
    string LoadFile();
}
Run Code Online (Sandbox Code Playgroud)

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

[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";
    }
}
Run Code Online (Sandbox Code Playgroud)

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

创建组合容器

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

访问导出的零件

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"
Run Code Online (Sandbox Code Playgroud)