关于Activator.CreateInstance到底创建的是什么的一个问题

2020年01月23日 11:41 0 点赞 2 评论 更新于 2025-11-21 21:30

昨天,有位同学提出了这样一个问题:

Controller c = Activator.CreateInstance(typeof(StarUpCommand)) as Controller;
c.Execute(data);

其中,StarUpCommand 类继承自 Controller 类,Controller 类有一个 abstract Execute() 抽象方法,而 StarUpCommand 类重写(override)了该 Execute() 方法。

问题是:c 现在被声明为 Controller 类型的一个实例,那么 c.Execute(data) 为什么会调用到 StarUpCommand.cs 里的 Execute() 方法呢?

我一开始没太理解这位同学的思路,尝试这样回答:

Activator.CreateInstance 方法创建了一个 StarUpCommand 对象的实例,然后通过 as 操作符将其类型转换为 StarUpCommand 的父类(即 Controller 类)。

显然,同学还是不太明白,继续追问:

c 为什么是 StarUpCommand 的实例而不是 Controller 的实例呢?Activator.CreateInstance(typeof(StarUpCommand)) 创建的是 StarUpCommand 类的实例,但经过 as 转换为 Controller 类型,并且 c 的声明也是 Controller 类,那么 c 应该是 Controller 类的实例才对啊?

这个问题问得很有意思,乍一看好像确实如此。于是,我继续举了个例子,该例子来源于 这里

假设 myObj 是一个已经存在的对象,我们来看下面的代码:

object myClass = new object();
myClass = Activator.CreateInstance(myObj.GetType());

这样一来,myClass 就完全拥有了 myObj 的方法和属性。

接下来,我们深入分析一下 Activator.CreateInstance 方法。该方法的定义如下:

public static object CreateInstance(Type type);

它返回的是一个 object 类型的对象。为什么要这样设计呢?这是因为 Activator.CreateInstance 方法通过反射机制(可以理解为一种在运行时分析类型信息的技术),摸清了指定类型(这里是 StarUpCommand 类)有哪些属性和方法,然后依据这些信息创建了一个对象实例并返回。但在这个过程中,该方法并没有直接使用 StarUpCommand 类的具体定义(就好像没有该类的“图纸”),所以只能返回一个通用的 object 类型对象。

既然这个对象实际上已经具有了 StarUpCommand 类的属性和方法,那么自然可以将其类型转换为它的父类或者基类。在我们的例子中,通过 as 操作符将其转换为 Controller 类型。虽然 c 被声明为 Controller 类型,但它实际上引用的是 StarUpCommand 类的实例,所以当调用 c.Execute(data) 时,会调用到 StarUpCommand 类中重写的 Execute() 方法,这体现了面向对象编程中的多态性。多态性允许我们通过基类的引用调用派生类中重写的方法,从而提高代码的灵活性和可扩展性。