自定义IOC容器 - 需要2/3类型的帮助

时间:2011-12-07 00:01:41

标签: c# inversion-of-control ioc-container

背景

为了帮助提高我对IOC的理解以及如何使用它,我想创建所有三种IOC技术的示例:构造函数注入,Setter注入和接口注入,而不必使用第三方框架。我想我有一个构造函数注入的基本示例,但在使用setter和接口注入方面苦苦挣扎。

我的问题

您将如何从头开始处理编写接口和setter注入?

这是我的想法,如果我走在正确的轨道上,请告诉我。

接口注入:

  1. 循环使用构造函数注入实例化的已解析对象,检查以查看interfaceDependencyMap中实现的接口
  2. 定义某种interfaceDependencyMap以将接口与实现相关联。
  3. 使用interfaceDependencyMap
  4. 解析实现
  5. 将适当的属性分配给使用构造函数注入初始化的对象
  6. Setter注射:

    1. 循环使用构造函数注入实例化的已解析对象
    2. 定义某种setterInjectionMap
    3. 使用构造函数映射
    4. 解析MethodInfo中的预期参数
    5. 调用传递已解析参数对象的setter方法
    6. 这是我到目前为止构造函数注入的内容

      public class Program
      {
          static void Main(string[] args)
          {
              //
              //instead of doing this:
              //
              //ICreditCard creditCard = new Visa();
              //var customer = new Customer(creditCard);
              //customer.Charge();
      
      
              var resolver = new Resolver();
      
              //map the types in the container
              resolver.Register<Customer, Customer>();
              resolver.Register<ICreditCard, Visa>();
      
              //because the customer constructor has an ICreditCard parameter
              //our container will automatically instantiate it recursively
              var customer = resolver.Resolve<Customer>();
      
              customer.Charge();
      
          }
      }
      
      public interface ICreditCard
      {
          string Charge();
      }
      
      public class Visa : ICreditCard
      {
          public string Charge()
          {
              return "Charging Visa";
          }
      }
      
      public class MasterCard : ICreditCard
      {
          public string Charge()
          {
              return "Charging MasterCard";
          }
      }
      
      public class Customer
      {
          private readonly ICreditCard _creditCard;
      
          public Customer(ICreditCard creditCard)
          {
              this._creditCard = creditCard;
          }
      
          public void Charge()
          {
              _creditCard.Charge();
          }
      }
      
      
      public class Resolver
      {
          private Dictionary<Type, Type> dependencyMap = new Dictionary<Type, Type>();
      
          public T Resolve<T>()
          {
              return (T) Resolve(typeof (T));
          }
      
          private object Resolve(Type typeToResolve)
          {
              Type resolvedType = null;
      
              try
              {
                  resolvedType = dependencyMap[typeToResolve];
              }
              catch
              {
                  throw new Exception(string.Format("could not resolve type {0}", typeToResolve.FullName));
              }
      
              var firstConstructor = resolvedType.GetConstructors().First();
              var constructorParameters = firstConstructor.GetParameters();
              if (constructorParameters.Count() == 0)
                  return Activator.CreateInstance(resolvedType);
      
              IList<object> parameters = constructorParameters.Select(parameterToResolve => Resolve(parameterToResolve.ParameterType)).ToList();
      
              return firstConstructor.Invoke(parameters.ToArray());
          }
      
          public void Register<TFrom, TTo>()
          {
              dependencyMap.Add(typeof (TFrom), typeof (TTo));
          }
      }
      

1 个答案:

答案 0 :(得分:3)

这是你想要的吗?

class Container
{
    class Registration
    {
        public Type RegistrationType;
        public Func<Container, object> Resolver;
    }

    List<Registration> registrations = new List<Registration>();

    public object Resolve(Type type)
    {
        return registrations
            .First(r => type.IsAssignableFrom(r.RegistrationType))
            .Resolver(this);
    }

    public T Resolve<T>()
    {
        return (T)Resolve(typeof(T));
    }

    public void Register<T>(Func<Container, T> registration) where T : class
    {
        registrations.Add(new Registration()
        {
            RegistrationType = typeof(T),
            Resolver = registration
        });
    }
}

用法:

interface IDependency
{
    string GetName();
}

class ConcreteDependency : IDependency
{
    public string GetName()
    {
        return "Concrete Dependency";
    }
}

class ConstructorExample
{
    readonly IDependency dependency;

    public ConstructorExample(IDependency dependency)
    {
        this.dependency = dependency;
    }

    public string GetString()
    {
        return "Consumer of " + dependency.GetName();
    }
}

class SetterExample
{
    public IDependency Dependency { get; set; }

    public string GetString()
    {
        return "Consumer of " + Dependency.GetName();
    }
}

[TestMethod]
public void MyTestMethod()
{
    var container = new Container();
    container.Register<IDependency>(c => new ConcreteDependency());
    container.Register(c => new ConstructorExample(c.Resolve<IDependency>()));
    container.Register(c => new SetterExample() { Dependency = c.Resolve<IDependency>() });

    var constructor = container.Resolve<ConstructorExample>();
    Assert.AreEqual("Consumer of Concrete Dependency", constructor.GetString());

    var setter = container.Resolve<SetterExample>();
    Assert.AreEqual("Consumer of Concrete Dependency", setter.GetString());
}

如果您想获得更高级的内容,我建议您获取以下任意内容:SimpleInjectorAutofacNinjectStructureMap