Reputation: 8243
I know that you can directly invoke the static constructor of a type and I know that you can create an instance of an object without calling the constructor, but is there a way to run the constructor of a type (.ctor
) on an already existing instance?
I'm looking for something like:
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");
}
I am aware that I should never really need to do this, I am more wondering if it is possible to re-invoke the constructor/initializer on an already created object.
Upvotes: 9
Views: 1746
Reputation: 101614
var ctor = typeof(T).GetConstructor(new[]{ typeof(int), typeof(string) });
ctor.Invoke(instance, new Object[]{ 7, "Bill" });
You're looking for .GetConstructor
.
Given the following object:
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;
}
}
Calling the ctor in the standard fashion results in the following:
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
// }
Now let' change d:
foo.d = 319009;
// foo {
// a=42,
// b="Hello, world!",
// c=11/27/2014 12:00:00 AM
// d=319009
// }
Calling the ctor again:
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
// }
Note that c
remains unchanged. This is because a & b are defined in the ctor, and, although not obvious, so is d (properties assigned at object level are actually assigned when ctor is called).
Upvotes: 5
Reputation:
A ConstructorInfo
object overloads MethodBase
's Invoke
method, but doesn't hide the inherited methods. You can simply make sure to pass the correct instance. Example:
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 });
}
}
However, as this answer also shows, this doesn't reset any of the object's fields, and a constructor may be written with the assumption that all fields are left at their default values. If you've got such a constructor, you will definitely need to make sure that you either don't mess with any fields, or re-set them if you have. If you've got an uninitialised object for which no constructor has been called yet, that should be fine.
Upvotes: 9