web-dev-qa-db-fra.com

MEF Constructeur Injection

J'essaie de comprendre l'attribut d'injection de constructeur de MEF. Je ne sais pas comment je lui dis de charger les paramètres du constructeur.

C'est la propriété que j'essaye de charger

[ImportMany(typeof(BUsers))]
public IEnumerable<BUsers> LoadBUsers { get; set; }

Voici le code que j'utilise pour importer les assemblys.

try
{
    var catalog = new AggregateCatalog();
    catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()));
    catalog.Catalogs.Add(new DirectoryCatalog("DI")); 
    var container = new CompositionContainer(catalog);
    container.ComposeParts(this);
}

Voici la classe que j'essaye de charger

[Serializable]
[Export(typeof(BUsers))]
public class EditProfile : BUsers
{
    [ImportingConstructor]
    public EditProfile(string Method, string Version)
    {            
        Version = "2";
        Action = "Edit";
        TypeName = "EditProfile";
    }
38
alpha

Lorsque vous utilisez l'attribut ImportingConstructor, les paramètres du constructeur deviennent des importations. Par défaut, ce que vous importez (le nom du contrat) dépend du type de paramètre ou de propriété dans lequel vous importez. Ainsi, dans ce cas, le type de contrat pour vos deux importations est une chaîne et il n'y a pas de réelle différence entre les premier et deuxième paramètres.

On dirait que vous essayez d'utiliser les importations pour fournir des valeurs de configuration, ce qui n'est pas nécessairement ce pour quoi elles ont été conçues. Pour le faire faire ce que vous voulez, vous devez remplacer le nom du contrat pour chacun des paramètres, comme ceci:

[ImportingConstructor]
public EditProfile([Import("Method")] string Method, [Import("Version")] string Version)
{ }

Ensuite, vous avez besoin d'exportations pour Method et Version dans votre conteneur. Une façon de faire est simplement de les ajouter directement:

var container = new CompositionContainer(catalog);
container.ComposeExportedValue("Method", "MethodValue");
container.ComposeExportedValue("Version", "2.0");
container.ComposeParts(this);

(Notez que ComposeExportedValue est en réalité une méthode d'extension définie dans la classe statique AttributedModelServices.)

Si vous souhaitez lire ces valeurs à partir d'un fichier de configuration, vous pouvez créer votre propre fournisseur d'exportation, qui lit la configuration et fournit les valeurs qu'il contient sous forme d'exportations vers le conteneur.

Une autre solution consiste à simplement importer une interface donnant un nom aux valeurs de configuration et à obtenir les valeurs dont vous avez besoin à partir du corps du constructeur.

55
Daniel Plaisted

J'aime la solution de Daniel. Cependant, une seule chose que je vois est le couplage étroit des noms de paramètres entre l'acteur (qui crée CompopositionContrainer ()) et la partie d'exportation avec [ImportingConstructor] pour un CTOR personnalisé. Par exemple, "Méthode" doit correspondre à deux à la fois. Il est difficile de conserver la partie exportation si l'acteur et la partie exportation sont dans des projets différents.

Si cela est possible, j'ajouterais le deuxième CTOR à la classe de pièce Export. Par exemple:

[Export(typeof(BUsers))] 
public class EditProfile : BUsers
{
    [ImportingConstructor]
    public EditProfile(EditProfileParameters ctorPars)
    : this(ctorPars.Method, ctorPars.Version) {}

    public EditProfile(string Method, string Version)
    {
        Version = "2";
        Action = "Edit";
        TypeName = "EditProfile";
    }

La classe de EditProfileParameters doit être simple: deux propriétés de Method et Version:

[Export]
public class EditProfileParameters{
   public string Method { get; set; }
   public string Version { get; set; }
}

Le point clé est d'ajouter l'attribut Export à la classe. MEF devrait alors pouvoir mapper cette classe sur le paramètre du CTOR de EditProfile.

Voici un exemple pour ajouter la partie exportée au conteneur:

var container = new CompositionContainer(catalog);
var instance1 = new EditProfileParameters();
// set property values from config or other resources
container.ComposeExportedValue(instance1);
container.ComposeParts(this);
23
David.Chu.ca

Bien que tard dans le jeu, voici une autre approche qui exploite une fonctionnalité moins connue de MEF: Property Exports

public class ObjectMother
{
    [Export]
    public static EditProfile DefaultEditProfile
    {
        get
        {
            var method = ConfigurationManager.AppSettings["method"];
            var version = ConfigurationManager.AppSettings["version"];

            return new EditProfile(method,version);
        }
    }
}

Aucune utilisation n'est requise pour que ObjectMother fonctionne, et aucun attribut n'est requis sur EditProfile.

0
bryanbcook