一,原理

使用反射加 xml 或者特性解析实现

二,实现

1,xml 实现

  • class 代码
// User 类namespace CsharpIOC{public class User{public string name { get; set; }public string age { get; set; }
    }
}复制代码
  • Xml容器类
public class XmlApplicationContext{/// <summary>/// bean 容器/// </summary>private static Dictionary<string, object> _beanContainer = new Dictionary<string, object>();public XmlApplicationContext(string xmlPath){
            XmlDocument xmlDoc = new XmlDocument();//读取 xml 文件xmlDoc.Load(xmlPath);//获取 xml 文件中所有的 bean 节点XmlNodeList nodeList = xmlDoc.SelectNodes("Bean");foreach (XmlNode node in nodeList)
            {//bean idstring beanId = string.Empty;//bean 的全类名,命名空间+类名string beanClass = string.Empty;foreach (XmlNode child in node.Attributes)
                {if (child.Name.Equals("id"))
                    {
                        beanId = child.Value;
                    }else if (child.Name.Equals("class"))
                    {
                        beanClass = child.Value;
                    }
                }//通过反射创建类的实例Type beanType = Type.GetType(beanClass);object bean = Activator.CreateInstance(beanType);//接下来调用set方法注入属性foreach (XmlNode child in node.ChildNodes)
                {//获取该类的所有方法var methods = beanType.GetMethods();foreach (var method in methods) {//默认的 set 方法名是 set_属性名,例如 set_nameif (method.Name.Equals($"set_{child.Name}")) {//调用 set 方法注入属性method.Invoke(bean,new object[] { child.InnerText});
                        }
                    }
                }//添加 bean 到容器中_beanContainer[beanId] = bean;
            }
        }/// <summary>/// 通过 bean id 获取 bean 实例/// </summary>/// <param name="beanId"></param>/// <returns></returns>public object getBean(string beanId) => _beanContainer[beanId];
    }复制代码
  • xml 配置
<?xml version="1.0" encoding="utf-8" ?><Bean id ="user" class="CsharpIOC.User">
  <name>任我行</name>
  <age>45</age></Bean>复制代码
  • 测试
XmlApplicationContext ctx = new XmlApplicationContext("Bean.xml");
User user = (User)ctx.getBean("user");
Console.WriteLine(user.name);
Console.WriteLine(user.age);复制代码

手动实现 C# 版简单版控制反转_C#

2,特性实现

  • 特性准备
/// <summary>/// 标记类可被容器扫描/// </summary>public class Component : Attribute{public string id { get; set; }
    }/// <summary>/// 标记字段的注入值/// </summary>public class Value : Attribute{public object value { get; set; }
    }复制代码
  • class
namespace CsharpIOC{
    [Component(id = "user")]public class User{
        [Value(value = "东方不败")]public string name { get; set; }
        [Value(value = "99")]public string age { get; set; }
    }
}复制代码
  • 特性容器类
public class AttributeaApplicationContext{/// <summary>/// bean 容器/// </summary>private static Dictionary<string, object> _beanContainer = new Dictionary<string, object>();public AttributeaApplicationContext(string nameSpace){//加载命名空间Assembly asm = Assembly.Load(nameSpace);//遍历命名空间下的类foreach (Type type in asm.DefinedTypes)
            {//找出带有 Componment 自定义特性标记的类var attribute = type.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.Equals(typeof(Component)));if (attribute != null)
                {//读取 Componment 中的 bean idstring beanId = attribute.NamedArguments.FirstOrDefault(na => na.MemberName.Equals("id")).TypedValue.Value.ToString();//实例化该 bean 对象object bean = Activator.CreateInstance(type);var properties = type.GetProperties();//遍历该 bean 的属性foreach (var property in properties)
                    {//找出带有 Value 自定义特性标记的 bean 属性var proAttribute = property.CustomAttributes.FirstOrDefault(ca => ca.AttributeType.Equals(typeof(Value)));if (proAttribute != null)
                        {//获取 Value 特性的值并注入var kv = proAttribute.NamedArguments.FirstOrDefault(na => na.MemberName.Equals("value"));var method = type.GetMethods().FirstOrDefault(m => m.Name.Equals($"set_{property.Name}"));if (method != null && kv != null) {
                                method.Invoke(bean,new object[] { kv.TypedValue.Value});
                            }
                        }
                    }//添加 bean 到容器中_beanContainer[beanId] = bean;
                }
            }
        }/// <summary>/// 通过 bean id 获取 bean 实例/// </summary>/// <param name="beanId"></param>/// <returns></returns>public object getBean(string beanId) => _beanContainer[beanId];
    }复制代码
  • 测试
AttributeaApplicationContext ctx = new AttributeaApplicationContext("CsharpIOC");
User user = (User)ctx.getBean("user");
Console.WriteLine(user.name);
Console.WriteLine(user.age);复制代码

手动实现 C# 版简单版控制反转_C#_02

三,结语

其实大部分已知的框架都是使用反射和设计模式组合实现的,IOC的核心便是反射,本文只是大概讲述其原理,实际其中还有很多的细节是没有讲到的,比如调用set方法时的参数类型转换,复杂的内嵌属性注入等等。