【问题标题】:Creating instance of type without default constructor in C# using reflection使用反射在 C# 中创建没有默认构造函数的类型实例
【发布时间】:2010-09-28 06:45:56
【问题描述】:

以下面的类为例:

class Sometype
{
    int someValue;

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

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

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

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

【问题讨论】:

  • FormatterServices.GetUninitializedObject 不允许创建未初始化的字符串。您可能会遇到异常:System.ArgumentException: Uninitialized Strings cannot be created. 请记住这一点。
  • 感谢您的提醒,但我已经分别处理字符串和基本类型了。

标签: c# reflection instantiation default-constructor


【解决方案1】:

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

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

【讨论】:

【解决方案2】:

使用 CreateInstance 方法的这个重载:

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

创建指定的实例 使用最好的构造函数输入 匹配指定的参数。

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

【讨论】:

  • 这个解决方案过度简化了问题。如果我不知道我的类型并且我说“只是在这个类型变量中创建一个类型的对象”怎么办?
【解决方案3】:

当我benchmarked 性能达到(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) 对于字符串将失败。因此对字符串进行特殊处理以返回空字符串。

【讨论】:

  • 奇怪的是,看一眼某人的代码可以节省一天的时间。谢谢你,先生!性能原因把我带到了你的帖子中,诀窍就完成了:) FormatterServices 和 Activator 类与编译表达式相比表现不佳,可惜的是到处都发现了 Activators。
  • @nawfal 关于您对字符串的特殊处理,我知道如果没有这种特殊处理,字符串会失败,但我只想知道:它是否适用于 all 其他类型?
  • @Sнаđошƒаӽ 不幸的是没有。给定的示例是准系统,.NET 有许多不同类型的类型。例如考虑一下,如果你传递一个委托类型,你将如何给你一个实例?或者如果构造函数抛出了你能做些什么呢?许多不同的方法来处理它。自从回答这个更新后,我已经在我的库中处理了更多的场景。它暂时没有在任何地方发布。
【解决方案4】:

很好的答案,但在 dot net compact 框架上无法使用。这是一个适用于 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);
    }
}

【讨论】:

  • 这是我调用非默认构造函数的方式。我不确定我是否想在不调用任何构造函数的情况下创建一个对象。
  • 如果您正在编写自定义序列化程序,您可能希望创建一个对象而不调用构造函数。
  • 是的,这正是这个问题所针对的用例场景:)
  • @Aistina 也许您可以将此信息添加到问题中?大多数人会反对在不调用他们的 ctor 的情况下创建对象,并且会花时间与您争论这一点,但您的用例实际上证明了这一点,所以我认为这与问题本身非常相关。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-03
  • 2020-12-15
  • 1970-01-01
相关资源
最近更新 更多