Mon post précédent contient une tentative d'utiliser une approche sans attribut (basée sur des conventions) pour configurer MEF : MEF 2 : importer beaucoup .
Mais il contient l'utilisation des attributs de métadonnées d'exportation dans la classe PluginMetadataAttribute nécessaire pour l'initialisation paresseuse du plugin par condition (nom spécifique, version).
Comment se débarrasser de la dépendance ExportAttribute ?
Réponses
Trop de publicités?J'ai trouvé trois solutions.
Solution 1 (utilisation de champs constants de classe, mauvaise solution) :
public class Plugin1 : IPlugin
{
public const string Name = "Plugin1";
public const string Version = "1.0.0.0";
public void Run()
{
Console.WriteLine("Plugin1 runed");
}
}
// ...
var builder = new RegistrationBuilder();
builder
.ForTypesDerivedFrom<IPlugin>()
.Export<IPlugin>(exportBuilder => {
exportBuilder.AddMetadata("Name", t => t.GetField("Name").GetRawConstantValue());
exportBuilder.AddMetadata("Version", t => t.GetField("Version").GetRawConstantValue());
});
Solution 2 (utilisation des propriétés de la classe, mauvaise solution) :
public interface IPluginMetadata
{
string Name { get; }
string Version { get; }
}
public interface IPlugin : IPluginMetadata
{
void Run();
}
public class Plugin1 : IPlugin
{
public string Name { get { return "Plugin 1"; } }
public string Version { get { return "1.0.0.0"; } }
public void Run()
{
Console.WriteLine("Plugin1 runed");
}
}
Et obtenir les valeurs des propriétés par la méthode décrite ici : https://stackoverflow.com/a/11162876/1986524
Solution 3 (utilisation des attributs, mieux mais pas tous satisfaits) :
using System;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Registration;
using System.Reflection;
namespace MEF2
{
public interface IPluginMetadata
{
string Name { get; }
string Version { get; }
}
public interface IPlugin
{
void Run();
}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class PluginMetadataAttribute : Attribute, IPluginMetadata
{
public string Name { get; set; }
public string Version { get; set; }
public PluginMetadataAttribute(string name, string version)
{
Name = name;
Version = version;
}
}
[PluginMetadata("Plugin1", "1.0.0.0")]
public class Plugin1 : IPlugin
{
public void Run()
{
Console.WriteLine("Plugin1 runed");
}
}
[PluginMetadata("Plugin2", "2.0.0.0")]
public class Plugin2 : IPlugin
{
public void Run()
{
Console.WriteLine("Plugin2 runed");
}
}
class Program
{
static void Main(string[] args)
{
var builder = new RegistrationBuilder();
builder
.ForTypesDerivedFrom<IPlugin>()
.Export<IPlugin>(exportBuilder => {
exportBuilder.AddMetadata("Name", t => t.GetCustomAttribute<PluginMetadataAttribute>().Name);
exportBuilder.AddMetadata("Version", t => t.GetCustomAttribute<PluginMetadataAttribute>().Version);
});
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly(), builder);
using (var container = new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection)) {
var plugins = container.GetExports<IPlugin, IPluginMetadata>();
foreach (var plugin in plugins) {
Console.WriteLine("{0}, {1}", plugin.Metadata.Name, plugin.Metadata.Version);
plugin.Value.Run();
}
}
}
}
}
La solution 3 contient le problème dans ce code :
.Export<IPlugin>(exportBuilder => {
exportBuilder.AddMetadata("Name", t => t.GetCustomAttribute<PluginMetadataAttribute>().Name);
exportBuilder.AddMetadata("Version", t => t.GetCustomAttribute<PluginMetadataAttribute>().Version);
})
Problèmes :
- Impossible d'annuler l'ajout de métadonnées en cas de métadonnées manquantes
- Code en double
t.GetCustomAttribute<PluginMetadataAttribute>()
-
Export<>
ne pas fournir de filtre
Si quelqu'un connaît d'autres solutions, veuillez nous écrire.
El Une approche libre d'attributs pour configurer le MEF auquel vous faites référence dans votre autre question comprend un exemple sur la façon d'ajouter des métadonnées sans utiliser d'attribut.
L'exemple montre une utilisation de la fonction PartBuilder.ExportProperties qui prend un Action<PropertyInfo, ExportBuilder>
en tant que paramètre et utiliser l'un des ExportBuilder.AddMetadata
pour ajouter des métadonnées pour l'exportation spécifique.
Ce n'est pas la seule façon d'ajouter des métadonnées. Toutes les méthodes d'exportation de PartBuilder ont une surcharge qui prend un Action<>
(ou une Action<,>) avec un paramètre ExportBuilder. Vous pouvez utiliser ces surcharges et ajouter vos métadonnées de manière similaire.