繁体   English   中英

如何在StructureMap中动态创建对象的实例?

[英]How to create an Instance of an Object in StructureMap Dynamically?

我有一个名为“ ImportRunner”的抽象类。

我有一个名为“ ScorecardRunner”的类的实现。

当我从XML文件中将对象类型作为字符串拉回时,如何在运行时获取诸如ScorecardRunner之类的实例,并且它可以是ImportRunner的任何实现?

我当前的代码如下。

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

当我尝试执行以下操作时,出现编译错误。

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

运算符“ <”不能应用于类型“方法组”和“类型”的操作数

谢谢汤姆

更好的方法是简单地创建一个负责确定正确的运行程序实例并将其注入的工厂,而不是散布用于基于运行时值创建实例并将其拖入StructureMap注册表的逻辑。

例如:

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

抱歉,我不同意答案的一般性主张。

如果您使用的是IoC,则不需要创建具体的工厂……这就是依赖注入的全部要点。

考虑这个小例子...

  • UnitOfWork将由StructureMap实例化
  • BankAccountApplication可以并且也应该由StructureMap实例化

Process.BankAccounts库-示例类:
注意Application classes属性如何引用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库-构建器:
当然,在单元测试中,您必须模拟第3方对象。 但是您可以并且应该使用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
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM