103

以下面的类为例:

class Sometype
{
    int someValue;

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

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

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

通常这会起作用,但是由于SomeType没有定义无参数构造函数,因此调用Activator.CreateInstance将引发类型异常,MissingMethodException并显示消息“没有为此对象定义无参数构造函数。 ”是否有另一种方法来创建这种类型的实例?将无参数构造函数添加到我的所有类中会有点糟糕。

4

4 回答 4

149

我最初在这里发布了这个答案,但这里是重印版,因为这不是完全相同的问题,但有相同的答案:

FormatterServices.GetUninitializedObject()将创建一个实例而不调用构造函数。我通过使用Reflector并挖掘了一些核心的 .Net 序列化类找到了这个类。

我使用下面的示例代码对其进行了测试,看起来效果很好:

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;
        }
    }
}
于 2008-12-24T01:44:41.027 回答
72

使用 CreateInstance 方法的这个重载:

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

使用与指定参数最匹配的构造函数创建指定类型的实例。

请参阅:http: //msdn.microsoft.com/en-us/library/wcxyzt4d.aspx

于 2008-12-24T01:44:50.327 回答
23

当我对它的性能进行基准测试(T)FormatterServices.GetUninitializedObject(typeof(T))时,它的速度较慢。同时编译的表达式会给你很大的速度改进,尽管它们只适用于具有默认构造函数的类型。我采用了混合方法:

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;
}

这意味着 create 表达式被有效地缓存,并且仅在第一次加载类型时才会产生惩罚。也会以有效的方式处理值类型。

称它为:

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

请注意,(T)FormatterServices.GetUninitializedObject(t)字符串将失败。因此,对字符串进行了特殊处理以返回空字符串。

于 2013-04-23T06:29:51.267 回答
4

很好的答案,但在点网紧凑框架上无法使用。这是一个适用于 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);
    }
}
于 2009-01-22T11:48:45.270 回答