DI/IoC, NHibernate and help in getting them to work together

后端 未结 6 1746
再見小時候
再見小時候 2020-12-30 16:20

I\'m trying to get my head around DI/IoC, NHibernate and getting them to work nicely together for an application that i\'m developing. I\'m quite new to both NHibernate and

6条回答
  •  爱一瞬间的悲伤
    2020-12-30 17:10

    A) If you're going to access the MarginCalculator through the Product domain object, you might as well cut out the middle man and let the DI/IOC container inject the MarginCalculator for you. You can even get rid of the MarginCalculatorAssembler because most DI/IOC containers do most of the boilerplate code of object construction for you.

    B and C) It's very possible. In fact, here's how your code would look like if you used LinFu:

    
    // No need to change the Transaction class
    public class Transaction
    {
        private double _margin;
        private Product _product;
        private Client _client;
    
        public double Margin { get; }
        public Product Product { get; }
        public Client Client { get; }
    
        public Transaction(Product p, Client c)
        {
            _product = p;
            _client = c;
        }
    
        public void CalculateMargin()
        {
            _margin = _product.MarginCalculator.CalculateMargin();
        }
    }
    

    It would be nice if you could get a DI/IOC to inject the product and client instances into the constructor--but before we do that, you need to register the dependencies with the container. Here's how you do it with LinFu.IOC:

    // Next, you'd have to tell LinFu to automatically register your product class:
    [Factory(typeof(Product))]
    public class ProductFactory : IFactory
    {
         object CreateInstance(IServiceRequest request)
         {
              // Grab a copy of the IRepository from the container
              var repository = container.GetService>();
    
              // Get the id (this assumes that your id is an Int32)
              var id = (int)request.Arguments[0];
    
              // Return the product itself
              return repository.GetById(id);
         }
    }
    
    // Do the same thing with the Client class
    // (Note: I did a simple cut and paste to keep things simple--please forgive the duplication)
    [Factory(typeof(Client))]
    public class ClientFactory : IFactory
    {
         object CreateInstance(IServiceRequest request)
         {
              // Grab a copy of the IRepository from the container
              var repository = container.GetService>();
    
              // Get the id (this assumes that your id is an Int32)
              var id = (int)request.Arguments[0];
    
              // Return the client itself
              return repository.GetById(id);
         }
    }
    
    [Factory(typeof(Transaction))]
    public class TransactionFactory : IFactory
    {
         object CreateInstance(IServiceRequest request)
         {
            // Note: Argument checking has been removed for brevity
            var container = request.Container;
            var arguments = request.Arguments;
            var productId = (int)arguments[0];
            var clientId = (int)arguments[1];
    
            // Get the product and the client
            var product = container.GetService(productId);
            var client = container.GetService(clientId);
    
            // Create the transaction itself
            return new Transaction(product, client);
         }
    }
    
    // Make this implementation a singleton
    [Implements(typeof(MarginCalculator), LifecycleType.Singleton)]
    public class ConcreteMarginCalculatorA : MarginCalculator
    {
        public override double CalculateMargin()
        {
            // Perform actual calculation
        }
    }
    

    Once you have all that code compiled in one of your assemblies, here's all you need to do to load it into the container:

    var container = new ServiceContainer();
    container.LoadFrom(AppDomain.CurrentDomain.BaseDIrectory, "YourAssembly.dll");
    

    ...Now for the fun part. In order to create your transaction object with the given product and client ID, here's the call you need to make to LinFu.IOC's container:

    int productId = 12345;
    int clientId = 54321;
    string serviceName = null;
    
    // Not pseudocode :)
    var transaction = container.GetService(serviceName, productId, clientId);
    

    What makes this interesting is that despite the number of dependencies you might have, LinFu's IOC container will handle 90% of the boilerplate code for you so you don't have to do all this stuff on your own. The best part is that all the implementations above will all be determined/resolved at runtime.

    You can practically swap implementations while the program is running, and you can even replace implementations without even recompiling your application. You can find more info here:

    http://www.codeproject.com/KB/cs/LinFu_IOC.aspx

    HTH :)

提交回复
热议问题