是否可以在已创建的实例上直接调用构造函数

本文关键字:调用 构造函数 实例 创建 是否 | 更新日期: 2023-09-27 18:32:13

我知道你可以直接调用一个类型的静态构造函数,我知道你可以创建一个对象的实例而不调用构造函数,但是有没有办法在已经存在的实例上运行一个类型的构造函数(.ctor)?

我正在寻找类似的东西:

public static void Reinitialize<T>(T instance)
{
  var initializer = typeof(T).GetHiddenConstructorThatDoesntNew(typeof(int), typeof(string));
  // call the constructor (int, string) on instance
  initializer.Invoke(instance, 7, "Bill");
}

我知道我永远不需要这样做,我更想知道是否可以在已经创建的对象上重新调用构造函数/初始值设定项。

是否可以在已创建的实例上直接调用构造函数

ConstructorInfo对象重载MethodBaseInvoke方法,但不隐藏继承的方法。您只需确保传递正确的实例即可。例:

using System;
using System.Reflection;
class A
{
    public int i;
    public A()
    {
        Console.WriteLine("A()");
    }
    private A(int j)
    {
        Console.WriteLine("A(" + j + "): i = " + i);
    }
}
static class Program
{
    static void Main(string[] args)
    {
        var a = new A();
        a.i = 3;
        var constructor = a.GetType().GetConstructor(BindingFlags.Instance | BindingFlags.Public |BindingFlags.NonPublic, null, new Type[] { typeof(int) }, null);
        constructor.Invoke(a, new object[] { 3 });
    }
}

但是,正如此答案还显示的那样,这不会重置对象的任何字段,并且可能会在编写构造函数时假设所有字段都保留为其默认值。如果你有这样一个构造函数,你肯定需要确保你要么不会弄乱任何字段,要么重新设置它们(如果有的话)。如果你有一个尚未调用构造函数的未初始化对象,那应该没问题。

var ctor = typeof(T).GetConstructor(new[]{ typeof(int), typeof(string) });
ctor.Invoke(instance, new Object[]{ 7, "Bill" });

你正在寻找.GetConstructor.


更多详情

给定以下对象:

public class Foo
{
    public Int32 a;
    public String b;
    public DateTime c;
    public Double d = 5318008;
    public Foo(Int32 a, String b)
    {
        this.a = a;
        this.b = b;
    }
}

以标准方式调用 ctor 会导致以下结果:

var foo = new Foo(42, "Hello, world!") { new DateTime(2014, 11, 26) };
// foo {
//   a=42,
//   b="Hello, world!",
//   c=11/27/2014 12:00:00 AM
//   d = 5318008
// }

现在让我们更改 d:

foo.d = 319009;
// foo {
//   a=42,
//   b="Hello, world!",
//   c=11/27/2014 12:00:00 AM
//   d=319009
// }

再次呼叫 CTOR:

typeof(Foo)
  .GetConstructor(new[]{ typeof(Int32), typeof(String) }).
  .Invoke(foo, new Object[]{ 84, "World, Hello!" });
// foo {
//   a=84,
//   b="World, hello!",
//   c=11/27/2014 12:00:00 AM // only unchanged property
//   d=5318008
// }

请注意,c保持不变。这是因为a&b是在ctor中定义的,虽然不明显,但d也是如此(在对象级别分配的属性实际上是在调用ctor时分配的)。