Подтвердить что ты не робот

Инъекция конструктора MEF

Я пытаюсь выяснить атрибут MEF Constructor Injection. Я понятия не имею, как я скажу, чтобы он загружал параметры конструктора.

Это свойство, которое я пытаюсь загрузить

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

Вот код, который я использую для импорта сборок.

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);
}

Вот класс, который я пытаюсь загрузить

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

Ответ 1

При использовании атрибута ImportingConstructor параметры для конструктора становятся импортными. По умолчанию то, что вы импортируете (название контракта), зависит от типа параметра или свойства, которое вы импортируете. Таким образом, в этом случае тип контракта для обоих ваших импорта является строкой, и нет никакой реальной разницы между первым и вторым параметрами.

Похоже, вы пытаетесь использовать импорт для доставки значений конфигурации, что не обязательно то, для чего оно предназначалось. Чтобы заставить его делать то, что вы хотите, вы должны переопределить имя контракта для каждого из параметров, например:

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

Затем вам нужно экспортировать метод и версию в свой контейнер. Один из способов сделать это - просто добавить их непосредственно:

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

(Обратите внимание, что ComposeExportedValue на самом деле является методом расширения, определенным в статическом классе AttributedModelServices.)

Если вы хотите прочитать эти значения из какого-либо файла конфигурации, вы можете создать своего собственного поставщика экспорта, который считывает конфигурацию и предоставляет значения в нем как экспорт в контейнер.

Альтернативным способом справиться с этим было бы просто импортировать интерфейс, обеспечивающий доступ к значениям конфигурации по имени, и получить нужные значения из тела конструктора.

Ответ 2

Мне нравится решение Даниэля; однако только одна вещь, которую я вижу, - это тесная связь имен параметров между актером (который создает CompopositionContrainer()) и Export part с [ImportingConstructor] для персонализированного CTOR. Например, "Метод" имеет два соответствия в обоих местах. Удерживать часть экспорта трудно, если актер и часть экспорта находятся в разностных проектах.

Если это возможно, я бы добавил второй CTOR в класс Export part. Например:

[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";
    }

Класс EditProfileParameters должен быть простым: два свойства метода и версии:

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

Ключевым моментом является добавление атрибута Export в класс. Затем MEF должен иметь возможность сопоставить этот класс с параметром EditProfile CTOR.

Вот пример добавления экспортированной части в контейнер:

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

Ответ 3

Несмотря на то, что в конце игры появился еще один подход, который использует менее известную функцию 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);
        }
    }
}

Для объекта ObjectMother для этого не требуются обычаи, и в EditProfile не требуются атрибуты.