A Microsoft incorporou no .NET Framework 4.0 o MEF (Managed Extensibility Framework), qual podemos utilizar para criar extensões em nossas aplicações e/ou utilizá-lo como um container de injeção de dependências. E ainda quando estava em suas primeiras versões, eu escrevi um artigo sobre ele, abordando os princípios básicos de sua utilização.
Basicamente o MEF trabalha com atributos, que decorados nos tipos envolvidos, importam ou exportam partes que são utilizadas pelo container para construir e, consequentemente, atribuir às classes que utilizam tais instâncias. Para exemplificar, veja o exemplo abaixo, onde temos uma interface que define a estrutura para logs de instruções em algum arquivo no disco:
public interface ILogger
{
string Path { get; set; }
void Write(string message);
}
E depois disso, temos as classes que implementam essa interface, criando os tipos concretos de acordo com a nossa necessidade. Abaixo temos essas implementações, e em cada classe que implementa a interface IFileLogger, explicitamente temos que decorá-las com o atributo ExportAttribute, para informar ao container que aquela classe é uma implementação de uma determinada interface.
[Export(typeof(IFileLogger))]
public class CsvLogger : IFileLogger { }
[Export(typeof(IFileLogger))]
public class XmlLogger : IFileLogger { }
Só que se tivermos várias implementações, estamos obrigados a especificar classe a classe esse atributo para que o runtime possa utilizá-las. A finalidade deste artigo é apenas para apresentar um atributo que também faz parte do MEF, chamado de InheritedExportAttribute, que pode ser aplicado diretamente na definição (interface), que diz ao container que todos aqueles que o implementarem, são candidatos a serem utilizados pela aplicação, e com isso, não há mais a necessidade de especificar classe a classe o atributo ExportAttribute.
[InheritedExport]
public interface ILogger
{
string Path { get; set; }
void Write(string message);
}
Utilizar este atributo faz com que todas as implementações sejam adicionadas ao container. Se você quiser trabalhar da forma inversa, ou seja, optar por marcar somente aquelas que não devem ser adicionadas, então você pode utilizar o atributo PartNotDiscoverableAttribute, que previne que a implementação não seja incluída no catalogo, e consequentemente, não utilizada pelo container. Exemplo:
[PartNotDiscoverable]
public class FakeLogger : IFileLogger { }