Moment For Technology

Manual implementation of C# version of the simple version of inversion of control

Posted on Aug. 8, 2022, 7:50 a.m. by John Maldonado
Category: The back-end Tag: c#

A, the principle of

Use reflection plus XML or feature parsing

Second, to achieve

1. XML implementation

  • The class code
/ / the User class
namespace CsharpIOC
{
    public class User
    {
        public string name { get; set; }
        public string age { get; set; }}}Copy the code
  • Xml container class
public class XmlApplicationContext
    {
        /// summary
        ///The bean container
        /// /summary
        private static Dictionarystring.object _beanContainer = new Dictionarystring.object ();public XmlApplicationContext(string xmlPath)
        {
            XmlDocument xmlDoc = new XmlDocument();
            // Read the XML file
            xmlDoc.Load(xmlPath);
            // Get all the bean nodes in the XML file
            XmlNodeList nodeList = xmlDoc.SelectNodes("Bean");
            foreach (XmlNode node in nodeList)
            {
                //bean id
                string beanId = string.Empty;
                // The full class name of the bean, namespace + class name
                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; }}// Create an instance of the class through reflection
                Type beanType = Type.GetType(beanClass);
                object bean = Activator.CreateInstance(beanType);
                // Then call the set method to inject the property
                foreach (XmlNode child in node.ChildNodes)
                {
                    // Get all the methods of the class
                    var methods = beanType.GetMethods();
                    foreach (var method in methods) {
                        // The default set method name is set_ attribute name, for example set_name
                        if (method.Name.Equals($"set_{child.Name}")) {
                            // Call the set method to inject properties
                            method.Invoke(bean,new object[] { child.InnerText}); }}}// Add beans to the container_beanContainer[beanId] = bean; }}/// summary
        ///Get the bean instance by bean ID
        /// /summary
        /// param name="beanId"/param
        /// returns/returns
        public object getBean(string beanId) = _beanContainer[beanId];
    }
Copy the code
  • The XML configuration

      
Bean id ="user" class="CsharpIOC.User"
  nameu-drive/name
  age45/age
/Bean
Copy the code
  • test
XmlApplicationContext ctx = new XmlApplicationContext("Bean.xml");
User user = (User)ctx.getBean("user");
Console.WriteLine(user.name);
Console.WriteLine(user.age);
Copy the code

2. Feature implementation

  • Features for
/// summary
    ///Tag classes can be scanned by containers
    /// /summary
    public class Component : Attribute
    {
        public string id { get; set; }}/// summary
    ///Marks the injected value of the field
    /// /summary
    public class Value : Attribute
    {
        public object value { get; set; }}Copy the code
  • class
namespace CsharpIOC{[Component(id = "user")]
    public class User{[Value(value = "Invincible in the East")]
        public string name { get; set; }
        [Value(value = "99")]
        public string age { get; set; }}}Copy the code
  • Property container class
public class AttributeaApplicationContext
    {
        /// summary
        ///The bean container
        /// /summary
        private static Dictionarystring.object _beanContainer = new Dictionarystring.object ();public AttributeaApplicationContext(string nameSpace)
        {
            // Load the namespace
            Assembly asm = Assembly.Load(nameSpace);
            // Iterate over classes in the namespace
            foreach (Type type in asm.DefinedTypes)
            {
                // Find the class with the Componment custom attribute tag
                var attribute = type.CustomAttributes.FirstOrDefault(ca = ca.AttributeType.Equals(typeof(Component)));
                if(attribute ! =null)
                {
                    // Read the bean ID in Componment
                    string beanId = attribute.NamedArguments.FirstOrDefault(na = na.MemberName.Equals("id")).TypedValue.Value.ToString();
                    // Instantiate the bean object
                    object bean = Activator.CreateInstance(type);
                    var properties = type.GetProperties();
                    // Iterate over the bean's properties
                    foreach (var property in properties)
                    {
                        // Find the bean property with the Value custom attribute tag
                        var proAttribute = property.CustomAttributes.FirstOrDefault(ca = ca.AttributeType.Equals(typeof(Value)));
                        if(proAttribute ! =null)
                        {
                            // Get the Value of the Value feature and inject it
                            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}); }}}// Add beans to the container_beanContainer[beanId] = bean; }}}/// summary
        ///Get the bean instance by bean ID
        /// /summary
        /// param name="beanId"/param
        /// returns/returns
        public object getBean(string beanId) = _beanContainer[beanId];
    }
Copy the code
  • test
AttributeaApplicationContext ctx = new AttributeaApplicationContext("CsharpIOC");
User user = (User)ctx.getBean("user");
Console.WriteLine(user.name);
Console.WriteLine(user.age);
Copy the code

Three, the conclusion

In fact, most of the known frameworks are implemented using a combination of reflection and design patterns. The core of IOC is reflection. This article only Outlines its principle, but there are many details that are not covered, such as parameter type conversion when calling set method, complex embedded property injection and so on.

Search
About
mo4tech.com (Moment For Technology) is a global community with thousands techies from across the global hang out!Passionate technologists, be it gadget freaks, tech enthusiasts, coders, technopreneurs, or CIOs, you would find them all here.