如何在只知道类型为System.Type的情况下获取该类型的默认值?

46

如果我想要一个返回给定类型默认值的方法,并且该方法是泛型的,我可以像下面这样返回默认值:

public static T GetDefaultValue()
{
  return default(T);
}

如果我只有System.Type对象,我能做类似的事情吗?

public static object GetDefaultValue(Type type)
{
  //???
}
3个回答

75

由于你只需要担心值类型(引用类型将会是 null),所以可以使用 Activator.CreateInstance 在它们上面调用默认构造函数。

public static object GetDefaultValue(Type type) {
   return type.IsValueType ? Activator.CreateInstance(type) : null;
}

编辑:Jon 当然是正确的。IsClass 不够全面,如果type 是接口,它会返回 False


22
最好使用!type.IsValueType来处理接口。 - Jon Skeet
1
改进建议:将“this”添加到参数中,使其成为扩展方法。 - Shaul Behr
似乎在dotnet core 2中有一个名为Type.GetDefaultValue()的新方法,但它没有出现在任何MSDN文档中。 - Ryan
1
还要注意,这实际上有一个边缘情况:https://github.com/dotnet/corefx/issues/31646#issuecomment-411443507如果结构体有默认构造函数,则会运行该构造函数。System.Runtime.Serialization.FormatterServices.GetUninitializedObject 实际上更准确。 - Ryan

7

这是我通常的做法。这样可以避免整个“IsValueType”或搜索构造函数的问题。

public static object MakeDefault(this Type type)
{
    var makeDefault = typeof(ExtReflection).GetMethod("MakeDefaultGeneric");
    var typed = makeDefault.MakeGenericMethod(type);
    return typed.Invoke(null, new object[] { });
}

public static T MakeDefaultGeneric<T>()
{
    return default(T);
}

你能解释一下这与Mark Brackett答案的不同/优劣吗? - rollsch
1
我不能说这是更好还是更差;我想这取决于你的需求。我的答案几乎肯定会比没有缓存的情况下慢。我特别喜欢这个解决方案的一件事情,那就是它确实使用了我们试图模拟的内置语言功能;而不是模拟它。 - jonfuller

0

如果没有泛型,你无法保证该类型具有无参数的构造函数,但是可以使用反射来搜索一个:

public static object GetDefaultValue(Type type)
{
    ConstructorInfo ci = type.GetConstructor( new Type[] {} );
    return ci.Invoke( new object[] {} );
}

我在控制台应用程序中尝试了这个方法,它返回该类的“默认”实例 - 假设它是一个类。如果您需要它也适用于引用类型,则需要使用其他技术。

3
引用类型的默认值是null,而不是类的实例。因此,如果按照您建议的去做,GetDefault(T)会返回null,而GetDefault(Type)会尝试创建一个实例(如果可能),这是错误的。您的技巧并不无用,但我认为它更像是一种“T GetInstance(T) where T : new() {return new T();}”类型的方法。 - JohannesH

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