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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/390578/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 01:41:07  来源:igfitidea点击:

Creating instance of type without default constructor in C# using reflection

c#reflectioninstantiationdefault-constructor

提问by Aistina

Take the following class as an example:

以下面的类为例:

class Sometype
{
    int someValue;

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

I then want to create an instance of this type using reflection:

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

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

Normally this will work, however because SomeTypehas not defined a parameterless constructor, the call to Activator.CreateInstancewill throw an exception of type MissingMethodExceptionwith the message "No parameterless constructor defined for this object." Is there an alternative way to still create an instance of this type? It'd be kinda sucky to add parameterless constructors to all my classes.

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

采纳答案by Jason Hymanson

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 Reflectorand digging through some of the core .Net serialization classes.

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

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

回答by Nick

Use this overload of the CreateInstance method:

使用 CreateInstance 方法的重载:

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

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

回答by Autodidact

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

很好的答案,但在 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);
    }
}

回答by nawfal

When I benchmarkedperformance 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:

当我对它的性能进行基准测试时(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;
}

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.

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

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.

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