Типы загрузки MEF, которые реализуют интерфейс и соответствуют атрибутам

Допустим, у меня есть интерфейс IFileLoader и атрибут FileTypeAttribute

И я реализую IFileLoader в JPEGLoader с помощью [FileType(". Jpg")]

Могу ли я использовать MEF для загрузки класса (JPEGLoader), который реализует IFileLoader и соответствует.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 ответ

Решение

Можно получить нужный загрузчик файлов, используя MEFи Attachnig Metadata на экспортируемые части.

Создать интерфейс метаданных и атрибут.

public interface IFileTypeMetadata
{
    string FileExtension { get; }
} 

Интерфейс может содержать столько свойств, сколько вам нужно. Для этой конкретной проблемы он содержит только одно свойство FileExtension, Важно, чтобы собственность имела только getter, MEF предназначен для предотвращения изменения метаданных во время выполнения. Затем создайте атрибут, содержащий метаданные:

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"
Другие вопросы по тегам