事先检查`System.Activator.CreateInstance(Of T)`是否会失败

时间:2011-05-24 16:52:10

标签: c# .net vb.net

我有一个类型(人类),我想知道我是否可以System.Activator.CreateInstance(Of Human)()。所以基本上我想检查Human是否有一个公共无参数构造函数/或带有可选参数的公共构造函数,这些参数可以在不给出任何参数的情况下调用New Human

是否有可能事先检查System.Activator.CreateInstance(Of T)是否会失败? (我的意思是除了将语句System.Activator.CreateInstance(Of Human)()包装在Try Catch中当然......)

我试过这个,但它不起作用:

Option Strict On : Option Explicit On
Module Test
    Public Class Human
        Public Sub New(Optional ByVal a As Integer = 1)

        End Sub
    End Class
    Public Sub Main()
        Dim c = GetType(Human).GetConstructor(System.Type.EmptyTypes)
        MsgBox(c Is Nothing)
    End Sub
End Module

4 个答案:

答案 0 :(得分:7)

检查构造函数是否为空或所有参数都是可选的:

var hasEmptyOrDefaultConstr = 
  typeof(Human).GetConstructor(Type.EmptyTypes) != null || 
  typeof(Human).GetConstructors(BindingFlags.Instance | BindingFlags.Public)
    .Any (x => x.GetParameters().All (p => p.IsOptional));

答案 1 :(得分:3)

您可以检查并确保您的类型Human具有可访问的无参数构造函数。最简单的方法是创建一个通用方法并添加约束where T : new()

编辑:

您可以像这样手动检查无参数构造函数

if(typeof(Human).GetType().GetConstructor(Type.EmptyTypes) !=null)
{
  ...      
}

答案 2 :(得分:3)

请注意,Activator.CreateInstance<T>()Activator.CreateInstance(Type)仅适用于无参数构造函数。在这个意义上,只有可选参数的构造函数 not 无参数。

可选参数(或参数)由调用站点上的C#编译器解析。但是,在使用反射调用构造函数时,没有编译器涉及这种方式。

如果您使用以下代码,则会得到一个MissingMethodException,表示没有定义无参数构造函数:

namespace ConsoleApplication1
{
    public class Foo
    {
        public Foo(int optional = 42)
        {
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Activator.CreateInstance<Foo>(); // causes MissingMethodException
        }
    }
}

换句话说,可选参数是编译器,而不是CLR。

有关“带有可选参数的极端情况”的更多信息,请参阅Eric Lippert最近的博客系列:

http://ericlippert.com/2011/05/09/optional-argument-corner-cases-part-one/

说到这一点,你可能能够以某种方式使用更多的反射来复制所需的行为,并为构造函数调用手动创建所需的参数。编译器会在程序集中放置一些可用于此目的的属性,我猜。

示例:

public class Foo
{
    public Foo([Optional, DefaultParameterValue(5)] int optional)
    {
        Console.WriteLine("Constructed");
    }
}

答案 3 :(得分:1)

我使用反射创建了一个快速控制台应用程序,以测试类型上的无参数构造函数。这是你需要的吗?

using System;
using System.Linq;

namespace ConsoleApplication
{
    public class HasPublicParameterlessContructorClass
    {
    }

    public class DoesntHavePublicParameterlessContructorClass
    {
        private int someField;

        public DoesntHavePublicParameterlessContructorClass(int someParameter)
        {
            someField = someParameter;
        }
    }

    class Program
    {
        public static bool HasPublicParameterlessContructor(Type t)
        {
            return t.GetConstructors().Any(constructorInfo => constructorInfo.GetParameters().Length == 0);
        }

        static void Main()
        {
            Console.WriteLine(HasPublicParameterlessContructor(typeof(HasPublicParameterlessContructorClass)));
            Console.WriteLine(HasPublicParameterlessContructor(typeof(DoesntHavePublicParameterlessContructorClass)));
        }
    }
}