使用反射在 C # 中创建没有缺省构造函数的类型实例

以下列课程为例:

class Sometype
{
int someValue;


public Sometype(int someValue)
{
this.someValue = someValue;
}
}

然后,我想使用反射创建这种类型的实例:

Type t = typeof(Sometype);
object o = Activator.CreateInstance(t);

通常情况下,这会起作用,但是因为 SomeType没有定义一个无参数的构造函数,对 Activator.CreateInstance的调用会抛出一个 MissingMethodException类型的异常和消息“ 没有为此对象定义无参数构造函数。”。还有其他方法来创建这种类型的实例吗?将无参数构造函数添加到我所有的类中有点糟糕。

96237 次浏览

I originally posted this answer here, but here is a reprint since this isn't the exact same question but has the same answer:

FormatterServices.GetUninitializedObject() will create an instance without calling a constructor. I found this class by using Reflector and digging through some of the core .Net serialization classes.

I tested it using the sample code below and it looks like it works great:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.Serialization;


namespace NoConstructorThingy
{
class Program
{
static void Main(string[] args)
{
MyClass myClass = (MyClass)FormatterServices.GetUninitializedObject(typeof(MyClass)); //does not call ctor
myClass.One = 1;
Console.WriteLine(myClass.One); //write "1"
Console.ReadKey();
}
}


public class MyClass
{
public MyClass()
{
Console.WriteLine("MyClass ctor called.");
}


public int One
{
get;
set;
}
}
}

Use this overload of the CreateInstance method:

public static Object CreateInstance(
Type type,
params Object[] args
)

Creates an instance of the specified type using the constructor that best matches the specified parameters.

See: http://msdn.microsoft.com/en-us/library/wcxyzt4d.aspx

Good answers but unusable on the dot net compact framework. Here is a solution that will work on CF.Net...

class Test
{
int _myInt;


public Test(int myInt)
{
_myInt = myInt;
}


public override string ToString()
{
return "My int = " + _myInt.ToString();
}
}


class Program
{
static void Main(string[] args)
{
var ctor = typeof(Test).GetConstructor(new Type[] { typeof(int) });
var obj = ctor.Invoke(new object[] { 10 });
Console.WriteLine(obj);
}
}

When I benchmarked performance of (T)FormatterServices.GetUninitializedObject(typeof(T)) it was slower. At the same time compiled expressions would give you great speed improvements though they work only for types with default constructor. I took a hybrid approach:

public static class New<T>
{
public static readonly Func<T> Instance = Creator();


static Func<T> Creator()
{
Type t = typeof(T);
if (t == typeof(string))
return Expression.Lambda<Func<T>>(Expression.Constant(string.Empty)).Compile();


if (t.HasDefaultConstructor())
return Expression.Lambda<Func<T>>(Expression.New(t)).Compile();


return () => (T)FormatterServices.GetUninitializedObject(t);
}
}


public static bool HasDefaultConstructor(this Type t)
{
return t.IsValueType || t.GetConstructor(Type.EmptyTypes) != null;
}

This means the create expression is effectively cached and incurs penalty only the first time the type is loaded. Will handle value types too in an efficient manner.

Call it:

MyType me = New<MyType>.Instance();

Note that (T)FormatterServices.GetUninitializedObject(t) will fail for string. Hence special handling for string is in place to return empty string.