【问题标题】:Custom IOC container - need help on 2/3 types自定义 IOC 容器 - 需要 2/3 类型的帮助
【发布时间】:2011-12-07 00:01:41
【问题描述】:

背景

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

我的问题

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

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

接口注入:

  1. 循环遍历使用构造函数注入实例化的解析对象,检查 interfaceDependencyMap 中实现了哪些接口
  2. 定义某种 interfaceDependencyMap 以将接口与实现相关联。
  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));
    }
}

【问题讨论】:

  • 有什么办法可以重新打开这个吗?
  • @EricRomanowski:请参阅以下原因,了解问题为何被关闭;如果您可以在问题中解决这些原因,那么其他人可以投票重新开放它,前提是他们认为它符合 SO 问题的标准。
  • 你不能,至少不能直接。但是,如果其他人(具有足够高的代表)认为编辑后的答案现在是一个真正的问题,他们可以投票重新开放。或者您可以使用自定义消息将其标记为版主注意。
  • 我重新格式化并重新表述了我的问题。抱歉,我在背景信息中暗示了一个问题。
  • 显然这是 c# 最保守的秘密 =)

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


【解决方案1】:

这就是你要找的吗?

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

【讨论】:

  • 非常感谢。过去三天我一直在努力弄清楚如何为接口和 setter 编写泛型(不确定这是否是正确的术语)。
猜你喜欢
  • 1970-01-01
  • 2018-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-18
  • 1970-01-01
  • 2010-09-16
  • 2012-02-16
相关资源
最近更新 更多