Типы загрузки 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"