2016-05-16 5 views
1

У меня есть абстрактный класс под названием «ImportRunner».Как создать экземпляр объекта в StructureMap динамически?

У меня есть реализация класса под названием «ScorecardRunner».

Как я могу во время выполнения получить экземпляр класса, такого как ScorecardRunner, когда я возвращаю Object Type обратно как String из XML-файла, и это может быть любая реализация ImportRunner?

Мой текущий код выглядит следующим образом.

var importer = container.GetInstance<ImportRunner>(); 

Когда я пытаюсь сделать что-то вроде ниже, я получаю ошибку компиляции.

var importer = container.GetInstance<Type.GetType("Importer.ScorecardRunner")>(); 

Оператор «<» не может быть применен к операндам типа «группы методов» и «Типа»

Спасибо, Том

ответ

3

Вместо того, чтобы распространять свою логику для создания экземпляр, основанный на значениях времени выполнения, и обуславливая его в реестре StructureMap, лучшим подходом было бы просто создать фабрику, отвечающую за определение правильного экземпляра runner и его внедрение.

Например:

public class XmlReader 
{ 
    public bool IsScoreCard { get; set; } 
} 

public abstract class ImportRunner 
{ 
} 

public class ScorecardRunner : ImportRunner 
{ 
} 

public class DefaultRunner : ImportRunner 
{ 
} 

public class RunnerFactory 
{ 
    private readonly XmlReader _reader; 

    public RunnerFactory(XmlReader reader) 
    { 
     _reader = reader; 
    } 

    public ImportRunner Resolve() 
    { 
     if (_reader.IsScoreCard) 
      return new ScorecardRunner(); 

     return new DefaultRunner(); 
    } 
} 

Затем настройте его следующим образом в реестре:

this.For<ImportRunner>().Use(ctx => ctx.GetInstance<RunnerFactory>().Resolve()); 
+0

Действительно 'For '? Пахнет как несоответствие типа. – Jarekczek

1

Я извиняюсь, но я не согласен с ответами общее утверждение.

Вам не нужно создавать конкретные заводы, если вы используете IoC ... это и есть цель инъекции зависимостей.

Рассмотрим небольшой пример ...

  • The UnitOfWork будет инстанцирован по StructureMap
  • BankAccountApplication может & также должен быть создан с помощью StructureMap

Process.BankAccounts Библиотека - Класс образца:
Обратите внимание, как класс UnitOfWork ссылается на Appl Appl свойство классов.

public class BankAccountApplication : IAccountApplication 
{ 
    #region <Fields & Constants> 

    private string StartingBalanceInvalidFormat = "A Starting Balance of {0} is invalid."; 
    private string AnnualPercentageRateInvalidFormat = "The Annual Percentage Rate of {0} is invalid."; 

    #endregion 

    #region <Properties> 

    [SetterProperty] 
    public IDemoDbUnitOfWork UnitOfWork { get; set; } 

    #endregion 

    #region <Methods> 

    public BankAccount CreateNew(AccountType bankAccountType, string ownerFullName, decimal startingBalance, decimal annualPercentageRate, string executedBy) 
    { 
     TraceHandler.TraceIn(TraceLevel.Info); 

     if (string.IsNullOrWhiteSpace(ownerFullName)) 
      throw new ArgumentNullException("Owner Full Name"); 

     if (startingBalance < 0.0M) 
      throw new ArgumentException(string.Format(StartingBalanceInvalidFormat, startingBalance)); 

     if (annualPercentageRate <= 0.0M) 
      throw new ArgumentException(string.Format(AnnualPercentageRateInvalidFormat, annualPercentageRate)); 

     var account = new BankAccount(); 

     try 
     { 
      BankAccountType accountType = GetAccountType(bankAccountType); 

      account.AnnualPercentageRate = annualPercentageRate; 
      account.Balance = startingBalance; 
      account.BankAccountTypeId = accountType.BankAccountTypeId; 
      account.OwnerFullName = ownerFullName; 
      account.ExecutedByName = executedBy; 
      account.ExecutedDatetime = DateTime.UtcNow; 

      UnitOfWork.BankAccounts.Add(account); 
      UnitOfWork.SaveChanges(); 
     } 
     catch (Exception ex) 
     { 
      TraceHandler.TraceError(ex); 
     } 
     finally 
     { 
      TraceHandler.TraceOut(); 
     } 

     return account; 
    } 

    public IEnumerable<BankAccount> FindOverdrafts(IAccountAlgorithm overdraftAlgorithm) 
    { 
     TraceHandler.TraceIn(TraceLevel.Info); 

     var accounts = new List<BankAccount>(); 

     try 
     { 
      var entities = UnitOfWork.BankAccounts.GetAll().ToList(); 

      entities.ForEach(e => { 

       IAlgorithmResult calculation = overdraftAlgorithm.Calculate(e.Balance); 

       if (calculation.Result) 
        accounts.Add(e); 
      }); 
     } 
     catch (Exception ex) 
     { 
      TraceHandler.TraceError(ex); 
     } 
     finally 
     { 
      TraceHandler.TraceOut(); 
     } 

     return accounts.AsEnumerable(); 
    } 

    private BankAccountType GetAccountType(AccountType bankAccountType) 
    { 
     var name = bankAccountType.ToStringValue(); 

     // In this case I am going to assume all accounts are properly mapped -> First() 
     return UnitOfWork.BankAccountTypes.GetAll().Where(a => a.BankAccountTypeName == name).First(); 
    } 

    #endregion 
} 

Process.BankAccounts Библиотека - ContainerRegistry:
Этот ContainerRegistry сканирует сборку & «устанавливает вверх» корневые интерфейсы, а затем использует свои команды для более «явных» инструкций.

public class ContainerRegistry : Registry 
{ 
    #region <Constructors> 

    public ContainerRegistry() 
    { 
     Scan(
      scan => 
      { 
       scan.TheCallingAssembly(); 
       scan.WithDefaultConventions(); 
       scan.LookForRegistries(); 
       scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("Bushido.Common", true, null)); 
       scan.AssembliesFromApplicationBaseDirectory(f => f.FullName.StartsWith("Bushido.Process", true, null)); 
       scan.AddAllTypesOf(typeof(IAccountApplication)); 
       scan.AddAllTypesOf(typeof(IAccountAlgorithm)); 
       scan.SingleImplementationsOfInterface(); 
      }); 

     ForSingletonOf(typeof(IDbContext)).Use(typeof(DemoDbContext)); 

     For(typeof(IDemoDbUnitOfWork)).Use(typeof(DemoDbUnitOfWork)); 
     For(typeof(IRepository<>)).Use(typeof(GenericRepository<>)); 
    } 

    #endregion 
} 

UnitTest Библиотека - Строитель:
Конечно, в модульном тесте, вы должны Макет 3rd объекты партии. Но вы можете & использовать IoC для этого.

public partial class Builder 
    { 
     #region <Methods> 

     public T CreateInstance<T>(IDemoDbUnitOfWork unitOfWork, bool byFullName = false) 
     { 
      if (unitOfWork == null) 
       throw new ArgumentNullException("UnitOfWork"); 

      // Here, I am passing-in a MOCK of the UnitOfWork & "shimming" it into "T" via IoC 
      var container = IoC.Initialize(); 
      container.Inject(typeof(IDemoDbUnitOfWork), unitOfWork); 

      return container.GetInstance<T>(); 
     } 

     public Mock<IDemoDbUnitOfWork> CreateMockUnitOfWork() 
     { 
      var unitOfWork = new Mock<IDemoDbUnitOfWork>(); 

      // DBO Tables 
      var bankAccountRepository = BankAccountRepositoryBuilder.CreateMock(); 
      var bankAccountTypeRepository = BankAccountTypeRepositoryBuilder.CreateMock(); 

      unitOfWork.SetupAllProperties(); 

      // DBO Tables 
      unitOfWork.SetupGet(x => x.BankAccounts).Returns(bankAccountRepository.Object); 
      unitOfWork.SetupGet(x => x.BankAccountTypes).Returns(bankAccountTypeRepository.Object); 

      return unitOfWork; 
     } 

     #endregion 
    } 

UnitTest Библиотека - Тесты:
Теперь, через класс Builder, вы можете создать экземпляр классы красиво. И, следовательно, вы тщательно очищаете тесты.

public void BankAccountApplication_CreateNew_Invalid_StartingBalance() 
{ 
    // ----- 
    // ARRANGE 

    var unitOfWork = Builder.CreateMockUnitOfWork(); 
    var application = Builder.CreateInstance<BankAccountApplication>(unitOfWork); 

    // ----- 
    // ACT 
    var account = application.CreateNew(AccountType.Checking, "Scrooge McDuck", -100.00M, 3.00M, Builder.ExecutedBy); 

    // ----- 
    // ASSERT 

    ...put your asserts here 
} 
Смежные вопросы