如何检查类型是否有无参数构造函数?

8

因为我想避免出现异常,所以我想检查一个类型是否有无参构造函数。我该怎么做?

我需要类似这样的代码:

bool HasDefaultConstructor<TT>(TT source)
{
   return ???;
}

编辑:

我希望创建一个与源对象类型相同的对象,如果源对象没有默认构造函数,则使用default(TT)代替。

目前我拥有的是:

        static TT CreateObject<TT>(TT source)
    {
        try
        {
            if(!HasDefaultConstructor<TT>(source))
            {
                return default(TT);
            }
            return (TT)Activator.CreateInstance(source.GetType());
        }
        catch(Exception ex)
        {
            Trace.WriteLine("Exception catched!\r\n" + ex);
        }
        return default(TT);
    }
    static bool HasDefaultConstructor<TT>(TT source)
    {
        ConstructorInfo c = typeof(TT).GetConstructor(new Type[] { });

        return c != null;
    }

然而这个检查返回真,但是 CreateInstance 抛出异常。

没有无参构造函数

解决方案:

bool HasDefaultConstructor(Type t)
{
   return t.GetConstructor(Type.EmptyTypes) != null;
}

涉及许多递归函数和迭代,但在这个过程中,错误的泛型函数HasDefaultConstructor(类型为object)被调用。使用非泛型函数就解决了问题。

感谢大家的建设性帮助。


请澄清您的问题 - 您想如何调用构造函数?由于您期望在没有无参数构造函数的情况下抛出异常,我认为即使指定给 TT 的类型没有这样的构造函数,您仍希望代码仍然可以编译通过? - O. R. Mapper
如果没有默认构造函数,我想使用default(TT)。 - MTR
啊哈!那么请在你的问题中包含这些信息。它显著改变了问题的意义,并使任何涉及“new()”泛型约束的答案无效。 - O. R. Mapper
@MTR 请查看我的更新答案。 - Adi Lester
2个回答

13

GetConstructor(Type.EmptyTypes)会返回无参构造函数,如果不存在则返回null,因此您可以使用以下代码:

return typeof(TT).GetConstructor(Type.EmptyTypes) != null;

编辑

我猜你的问题是TTsource.GetType()实际上是两种不同的类型。source.GetType()可能派生自TT,但没有无参构造函数。所以你实际上需要检查source.GetType()

bool HasDefaultConstructor(Type t)
{
   return t.GetConstructor(Type.EmptyTypes) != null;
}

if(!HasDefaultConstructor(source.GetType()))
    ...

你是对的。在某些递归函数中,有关类型的信息丢失了。因此,调用了对象的通用函数(而不是实际类型的函数),GetType和TT确实不同。使用source.GetType()可以解决这个问题。 - MTR

9
使用反射来检查类型是否有一个无参数构造函数。使用Type.GetConstructor
bool HasDefaultConstructor<TT>()
{
    ConstructorInfo c = typeof(TT).GetConstructor(new Type[] { });
    // A constructor without any types defined: no parameters

    return c != null;
}

如果你只想创建 TT 的实例,可以使用 new 约束:
TT CreateUsingDefaultConstructor<TT>() where TT : new()
{
    return new TT();
}

Jeppe Stig Nielsen所建议的,您可以使用以下代码来查找不是public的构造函数。我认为,您应该将其作为最后的手段!
typeof(TT).GetConstructor( BindingFlags.Instance
                           | BindingFlags.NonPublic
                           | BindingFlags.Public
                         , null
                         , new Type[] { }
                         , null
                         )

3
当然,如果你也接受一个非公共的零参数构造函数,可以尝试使用 typeof(TT).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, new Type[] { }, null) - Jeppe Stig Nielsen
1
@JeppeStigNielsen:已将您的建议添加到答案中,并进行了归属。 - Patrick Hofman
@MTR:你有一个示例类吗? - Patrick Hofman
@MTR:同时不要使用source,请使用typeof(TT) - Patrick Hofman
我正在处理一个示例,因为这在简单情况下似乎有效,但在我的情况下不起作用。 - MTR
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接