• C#动态创建接口的实现实例对象


    本文简单介绍如何动态创建接口interface的实现实例对象,包含两个知识点:

    1.如何获取接口interface的所有实现实例对象?

    2.如何判断实例对象的构造函数是否有参数?

    准备工作

      首先新建一个名为IAnimal的interface接口对象,并定义一个Cry方法。

    namespace DynamicCreate
    {
        /// <summary>
        /// 动物
        /// </summary>
        public interface IAnimal
        {
            /// <summary>
            /// 叫
            /// </summary>
            public void Cry();
        }
    }

      然后,我们分别新建一个Dog,Cat对象,并分别实现Cry方法。

      其中,Dog的构造函数中包含一个名为name的参数。

    namespace DynamicCreate
    {
        /// <summary>
        /// 狗
        /// </summary>
        public class Dog : IAnimal
        {
            /// <summary>
            /// 名字
            /// </summary>
            private string _name { get; }
    
            /// <summary>
            /// 有参构造函数
            /// </summary>
            /// <param name="name">狗名</param>
            public Dog(string name)
            {
                _name = name;
            }
    
            /// <summary>
            /// 狗叫
            /// </summary>
            public void Cry()
            {
                Console.WriteLine($"{_name}汪汪汪");
            }
        }
    }
    

      Cat的构造函数则为无参构造函数。

    namespace DynamicCreate
    {
        /// <summary>
        /// 猫
        /// </summary>
        public class Cat : IAnimal
        {
            /// <summary>
            /// 无参构造函数
            /// </summary>
            public Cat()
            {
    
            }
    
            /// <summary>
            /// 猫叫
            /// </summary>
            public void Cry()
            {
                Console.WriteLine("喵喵喵");
            }
        }
    }

      常规的调用方法如下所示。

    IAnimal animal_Dog = new Dog("旺财");
    animal_Dog.Cry();
    IAnimal animal_Cat = new Cat();
    animal_Cat.Cry();

      运行结果如图所示

       如果我们想要一次性将所有实现了IAnimal接口对象Cry方法的实例全部执行一遍,只能一个对象一个对象的初始化,然后调用cry方法。这样太麻烦,我们可以通过动态创建对象并执行对象的方法来实现这个效果。   

    下面,我们将开始动态创建所有实现。第一步,我们需要先获取到所有实现了IAnimal实例对象。

    1.如何获取接口interface的所有实现实例对象?

      通过反射来获取当前项目中的程序集对象列表,并根据程序集对象的类型来获取继承或实现了IAnimal接口的对象列表。

    //获取实现接口IAnimal的实例对象
    var types = AppDomain.CurrentDomain.GetAssemblies()
                            .SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IAnimal))))
                            .ToList(); 
    

      我们将结果打印出来看一下

    foreach (Type t in types)
    {
        Console.WriteLine(t.Name);
    }
    

      

        现在,我们已经得到了所有实现IAnimal接口的实例对象。讲道理来说,我们就可以用Activator动态创建这些对象了。我们可以使用下面的代码来实现批量动态创建对象。

    foreach (Type t in types)
    {
        var animal = (IAnimal)Activator.CreateInstance(t)!;
        animal.Cry();
    }
    

      然而,却出现一个错误提示:Dog不包含一个无参构造函数。

       所以,创建时需要将Dog的构造函数参数name传递进去,如下所示。

    foreach (Type t in types)
    {
        var animal = (IAnimal)Activator.CreateInstance(t, new object[] { "阿黄" })!;
        animal.Cry();
    }
    

      然而,再次提示:Cat的构造函数不存在。

       这是因为Cat不包含一个带参数的构造函数,所示无法初始化Cat对象。所以,我们需要判断对象是否是有参构造函数或无参构造函数。

    2.如何判断实例对象的构造函数是否有参数?

      我们可以通过GetConstructors方法来获取对象的构造函数集合,并通过GetParameters方法获取到构造函数的参数集合,判断构造函数的参数集合是否为空即可判断该对象的构造函数是否为有参或无参构造函数。

    foreach (Type v in types)
    {
        if (v.GetConstructors().Any(x => x.GetParameters().Any()))
        {
            Console.WriteLine($"{v.Name}=>有参构造函数");
        }
        else
        {
            Console.WriteLine($"{v.Name}=>无参构造函数");
        }
    }
    

      

        现在,我们可以愉快的创建对象,并调用对象的方法了。

    foreach (Type t in types)
    {
        IAnimal animal;
        if (t.GetConstructors().Any(x => x.GetParameters().Any()))
        {
            //有参构造函数
            //动态创建IAnimal的有参构造函数实现实例对象Dog
            animal = (IAnimal)Activator.CreateInstance(t, new object[] { "阿黄" })!;
        }
        else
        {
            //无参构造函数
            //动态创建IAnimal的无参构造函数实现实例对象Cat
            animal = (IAnimal)Activator.CreateInstance(t, new object[] { })!;
        }
        animal.Cry();
    }
    

      

      

       最后,附上完整代码,请大神们不要喷我

      GitHub

      码云

    本文来自博客园,作者:摇曳de风筝,转载请注明原文链接:https://www.cnblogs.com/pinzi/p/15598531.html

  • 相关阅读:
    2018年左其盛读过评过的书(持续更新中)
    2星|《用场景营销引爆你的生意》:总共4个推荐案例,3个已经失败
    2018左其盛经管新书差评榜(持续更新中)
    3星|《十大全球CEO亲授企业高速成长的关键战略》:作为CEO,我也非常坦率地表明过家庭优先于工作
    2018左其盛好书榜(持续更新中)
    3星|《你的品牌需要一个讲故事的人》:有理论没案例
    《思考快与慢》前传,两位天才犹太心理学家的传奇人生与学术故事:4星|《思维的发现》
    C#如何在派生类中不显示父类的一些属性以及TypeDescriptor使用
    在XML里的XSD和DTD以及standalone的使用
    数据库操作之简单带参操作
  • 原文地址:https://www.cnblogs.com/pinzi/p/15598531.html
Copyright © 2020-2023  润新知