2016-05-16 27 views
1

私は "ImportRunner"と呼ばれる抽象クラスを持っています。StructureMapでオブジェクトのインスタンスを動的に作成する方法は?

"ScorecardRunner"というクラスの実装があります。

XMLファイルからStringとしてオブジェクト型を取り戻しているときに、ScorecardRunnerなどのクラスのインスタンスを実行時に取得するにはどうすればできますか?また、ImportRunnerの実装は可能ですか?

私の現在のコードは以下の通りです。

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

次のようなことをしようとすると、コンパイルエラーが発生します。

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

演算子「<」、「メソッドグループ」と 「種類」

おかげタイプのオペランドにトム・

答えて

3

の代わりに作成するためのロジックを拡散を適用することはできませんインスタンスをランタイム値に基づいて構造化マップのレジストリに登録すると、正しいランナーインスタンスを決定して注入するためのファクトリを作成するだけです。例えば

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を使用している場合、具体的なファクトリを作成する必要はありません。これは、依存性注入のポイント全体です。

は、この小さな例を考えてみましょう...

  • たUnitOfWorkはのStructureMap
  • BankAccountApplicationによってインスタンス化されますが&またのStructureMap

Process.BankAccountsライブラリによってインスタンス化されなければならないことができます - サンプルクラス:
ApplでUnitOfWorkクラスを参照する方法に注目してくださいクラスのプロパティ。

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の図書館 - ビルダー:もちろん
、ユニットテストでは、あなたがサードパーティのオブジェクトをモック必要があります。しかし、&はそれを行うために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のライブラリ - テスト:
今、ビルダークラスを介して、あなたは素敵なあなたのクラスをインスタンス化することができます。その結果、単体テストはうまくクリーンアップされます。

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 
} 
関連する問題