Вопрос

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

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

[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";
    }
Это было полезно?

Решение

Когда вы используете атрибут 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.)

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

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

Другие советы

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

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

[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 сможет сопоставить этот класс с параметром CTOR EditProfile.

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

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

Хоть и поздно, но вот еще один подход, использующий менее известную особенность MEF:Экспорт недвижимости

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 не требуются никакие атрибуты.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top