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

发布于 2024-12-19 18:49:24 字数 2911 浏览 3 评论 0原文

背景

为了帮助提高我对 IOC 及其使用方法的理解,我想创建一个包含所有三种 IOC 技术的示例:构造函数注入、Setter 注入和接口注入,而无需使用第三方框架。我想我有一个构造函数注入的基本示例,但在设置器和接口注入方面遇到了困难。

我的问题

您将如何从头开始解决编写接口和设置器注入问题?

这是我的想法,请告诉我我是否走在正确的道路上。

接口注入:

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

Setter 注入:

  1. 循环遍历使用构造函数注入实例化的已解析对象
  2. 定义某种 setterInjectionMap
  3. 使用构造函数映射从 MethodInfo 解析预期参数
  4. 调用传入解析的 setter 方法参数对象

这是迄今为止我所拥有的构造函数注入的内容

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

Background

To help improve my understanding of IOC and how to use it, I want to create an example of all three IOC techniques: Constructor injection, Setter injection, and Interface injection without having to use a third party framework. I think I have a basic example of constructor injection, but struggling with setter and interface injection.

My Question

How would you approach tackling writing interface and setter injection from the ground up?

Here's my thoughts, let me know if I'm on the right track.

Interface injection:

  1. Loop through resolved objects instantiated using constructor injection,check to see what interfaces are implemented in interfaceDependencyMap
  2. Define some sort of interfaceDependencyMap to associate an interface to the implementation.
  3. Resolve the implementation using interfaceDependencyMap
  4. Assign the appropriate property to the object initialized with constructor injection

Setter injection:

  1. Loop through resolved objects instantiated using constructor injection
  2. Define some sort of setterInjectionMap
  3. Resolve the expected parameter from MethodInfo using the constructor mappings
  4. Call the setter method passing in the resolved parameter object

Here's what I have so far for constructor injection

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

爱*していゐ 2024-12-26 18:49:24

这是您正在寻找的吗?

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

如果您想获得更高级的知识,我建议您获取其中任何一个的源代码:SimpleInjector,< a href="http://code.google.com/p/autofac/" rel="nofollow">Autofac, 注射StructureMap

Is this kind of what you're looking for?

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

Usage:

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

If you want to get more advanced, I would recommend getting the source of any of these: SimpleInjector, Autofac, Ninject, StructureMap.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文