C# 根据字符串生成对象——使用反射

在C#中,如果想根据类的字符串名动态生成类的示例对象,需要用到反射的知识。所谓反射,也就是利用程序集中的圆数据信息。凡是要用反射的程序,需要导入System.Reflection命名空间。

动态创建对象有两大类:Activator和Assembly。我更喜欢Activator类,先简单介绍下Assembly。

目录

1.Assembly的使用方法

1.1 假设你要反射一个 DLL 中的类,并且没有引用它(即未知的类型): 

1.2 若要反射当前项目中的类(即当前项目已经引用它了)可以为:

2. Activator的用法

3. 实例


1.Assembly的使用方法

1.1 假设你要反射一个 DLL 中的类,并且没有引用它(即未知的类型): 

Assembly assembly = Assembly.LoadFile("程序集路径,不能是相对路径"); // 加载程序集(EXE 或 DLL) 
dynamic obj = assembly.CreateInstance("类的完全限定名(即包括命名空间)"); // 创建类的实例 

1.2 若要反射当前项目中的类(即当前项目已经引用它了)可以为:

Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集 
dynamic obj = assembly.CreateInstance("类的完全限定名(即包括命名空间)"); // 创建类的实例,返回为 object 类型,需要强制类型转换。

也可以这么使用:

Type type = Type.GetType("类的完全限定名"); 
dynamic obj = type.Assembly.CreateInstance(type); 


2. Activator的用法

 Activator 类提供好几个动态创建对象的重载方法。

1:public static object CreateInstance(Type type);
2:public static object CreateInstance(Type type, params object[] args);

其中关键在于获得一个Type类型的参数,有了这个参数才能创建一个对应类型的实例。而获取Type对象有三种方式

1:Type type = Type.GetType("命名空间名称.类名");
2:Type type = typeof("类名");
3:Person p = new Person(); //通过对象来进行创建type
 Type type = p.GetType();

之所以更喜欢Activator是因为,它提供了带构造参数的方法,也就是可以将参数传递给构造函数。


3. 实例

假设有一个Animal基类,派生出三个类:Cat,Pig,Dog。给一个字符串数组,动态生成对应的实例对象。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;


namespace ReflectionTest
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> classNames = new List<string> { "Dog", "Cat","Pig" };

            Type t;
            int i=1;
            foreach (var s in classNames)
            {
                t = Type.GetType("ReflectionTest." + s);
                object[] para = new object[] {"啦啦啦",i++};
                Animal o = (Animal)Activator.CreateInstance(t, para);
                //上面这句也可写成 Animal o = (Animal)Activator.CreateInstance(t, "啦啦啦", i++);
                o.Bark();
            }
            

        }
    }


    public class Animal
    {
        public readonly int age = 0;
        public readonly string name = "";
        public Animal(string Name, int num)
        {
            age = num;
            name = Name;
        }
        public virtual void Bark()
        {
            Console.WriteLine($"     姓名:{name} \n     年龄:{age}");
           // Console.WriteLine($"ao,ao,ao!, hello ,my name is {name} and I am  {age} years old!");
        }
    }

    public class Dog:Animal
    {
        public Dog(string Name, int age) : base(Name, age) { }
        public override void Bark()
        {
            Console.WriteLine($"我是一条狗,天天汪汪汪!");
            base.Bark();
        }
    }
    public class Cat:Animal
    {
        public Cat(string Name, int age) : base(Name, age) { }
        public override void Bark()
        {
            Console.WriteLine("喵喵喵,爱吃鱼");
            base.Bark();
        }
    }
    public class Pig:Animal
    {
        public Pig(string Name, int age) : base(Name, age) { }
        public override void Bark()
        {
            Console.WriteLine("哼哼哼,爱睡懒觉");
            base.Bark();
        }
    }
}

运行结果如下:

我是一条狗,天天汪汪汪!
     姓名:hhuihhjhjh
     年龄:1
喵喵喵,爱吃鱼
     姓名:hhuihhjhjh
     年龄:2
哼哼哼,爱睡懒觉
     姓名:hhuihhjhjh
     年龄:3
请按任意键继续. . .

这里要说明一下,为什么要有一个公共的基类Animal,因为CreateInstance函数生成的对象类型默认为Object,需要强制转化为派生类,但是我们可能事先并不知道这个类的类型,但是知道它一定属于Animal类所以,可以这么做。反之,要是事先知道它是什么类型,就不需要动态生成了,直接使用new函数即可。

这也反映了一个局限:不同基类的类型,可以动态生成,但是没法转换为对应的类型。(或许是我没有找到可行的方法)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值