对于任何给定的类型,我想知道它的默认值。运行时类型的默认值
在C#中,有一个名为默认这样做的像
object obj = default(Decimal);
关键字,但我有一个类型(称为的myType)的实例,如果我说这个,
object obj = default(myType);
它不不工作
有没有这样做的好方法? 我知道一个巨大的开关块可以工作,但那不是一个好的选择。
对于任何给定的类型,我想知道它的默认值。运行时类型的默认值
在C#中,有一个名为默认这样做的像
object obj = default(Decimal);
关键字,但我有一个类型(称为的myType)的实例,如果我说这个,
object obj = default(myType);
它不不工作
有没有这样做的好方法? 我知道一个巨大的开关块可以工作,但那不是一个好的选择。
这确实只有两种可能:null
引用类型和new myType()
值类型(对应于0代表int,float等)所以你真的只需要考虑两种情况:
object GetDefaultValue(Type t)
{
if (t.IsValueType)
return Activator.CreateInstance(t);
return null;
}
(因为值类型总是有一个默认构造函数,所以对Activator.CreateInstance的调用永远不会失败)。
我发布了相同的解决方案,但我不确定如何处理可用的空白。事实证明,可变空值落入第一个分支,但Activator.CreateInstance(typeof(int?))实际返回null,因此全部结束。 – Josh 2010-03-22 06:08:27
@Josh:有趣......我对我的解决方案做了一个快速测试,'int?'出来了预期的'null',但我没有真正测试typeof(int?)。IsValueType'是否返回true,或者假。 – 2010-03-22 06:10:52
是的。这使您在运行时重新实现C#编译器的default()运算符。这很容易做到,但是,如果要延长违约规则以考虑新的场景,则必须更新代码。 – 2010-03-22 06:11:08
如何像...
class Program
{
static void Main(string[] args)
{
PrintDefault(typeof(object));
PrintDefault(typeof(string));
PrintDefault(typeof(int));
PrintDefault(typeof(int?));
}
private static void PrintDefault(Type type)
{
Console.WriteLine("default({0}) = {1}", type,
DefaultGenerator.GetDefaultValue(type));
}
}
public class DefaultGenerator
{
public static object GetDefaultValue(Type parameter)
{
var defaultGeneratorType =
typeof(DefaultGenerator<>).MakeGenericType(parameter);
return defaultGeneratorType.InvokeMember(
"GetDefault",
BindingFlags.Static |
BindingFlags.Public |
BindingFlags.InvokeMethod,
null, null, new object[0]);
}
}
public class DefaultGenerator<T>
{
public static T GetDefault()
{
return default(T);
}
}
它产生以下输出:
default(System.Object) =
default(System.String) =
default(System.Int32) = 0
default(System.Nullable`1[System.Int32]) =
你是什么意思的“默认值”?所有引用类型(“类”)都具有空值作为默认值,而所有值类型都将具有根据this table的默认值。
您提到的规则有一个明显的例外。也就是说,可为空的ValueType始终具有默认值null,而不是其基础ValueType的默认值。可为空的ValueType仍然是ValueType。还要记住,虽然泛型类定义(type.ContainsGenericParameters == true)在技术上被认为是一个引用类型,但它没有默认值,因为它不能直接实例化。有关更多详细信息和示例,请参阅http://stackoverflow.com/questions/2490244/default-value-of-a-type/7881481#7881481上的我的解决方案。 – 2011-10-24 21:01:36
...更类似Nullable
这里是一个将返回默认值可空类型的函数(换句话说,这两个Decimal
和Decimal?
返回0):
public static object DefaultValue(Type maybeNullable)
{
Type underlying = Nullable.GetUnderlyingType(maybeNullable);
if (underlying != null)
return Activator.CreateInstance(underlying);
return Activator.CreateInstance(maybeNullable);
}
您不希望为可为null的Type返回ValueType默认值,因为这不是正确的默认值。可空类型的正确缺省值为null。所以对于你的例子,Decimal应该有一个默认的0,但是十进制?应该有一个默认值为null。请参阅http://stackoverflow.com/questions/2490244/default-value-of-a-type/7881481#7881481中的我的解决方案,它也适用于所有可为空的类型。 – 2011-10-24 20:45:19
你也可以将其添加为扩展方法体系.TYPE:
public static class TypeExtensions
{
public static object GetDefaultValue(this Type t)
{
if (t.IsValueType && Nullable.GetUnderlyingType(t) == null)
return Activator.CreateInstance(t);
else
return null;
}
}
这'别的'让我疯狂:) – sam 2017-01-02 14:27:29
返回(t.IsValueType && Nullable.GetUnderlyingType(t)== null)? Activator.CreateInstance(t):null;如果你不喜欢它犹豫不决! – coalvilledave 2017-07-11 15:42:12
这不是关于只有一个'返回',这会使代码在这种情况下变得混乱。真的只是删除单词'else',因为如果你返回.. if(....)return Activator.CreateInstance(t);返回null; – sam 2017-07-12 07:29:39
在自己的系统中已经解决了这个问题,这里是在运行时,已对数以千计类型测试的正确判断任意类型的默认值的方法:
/// <summary>
/// [ <c>public static object GetDefault(this Type type)</c> ]
/// <para></para>
/// Retrieves the default value for a given Type
/// </summary>
/// <param name="type">The Type for which to get the default value</param>
/// <returns>The default value for <paramref name="type"/></returns>
/// <remarks>
/// If a null Type, a reference Type, or a System.Void Type is supplied, this method always returns null. If a value type
/// is supplied which is not publicly visible or which contains generic parameters, this method will fail with an
/// exception.
/// </remarks>
/// <example>
/// To use this method in its native, non-extension form, make a call like:
/// <code>
/// object Default = DefaultValue.GetDefault(someType);
/// </code>
/// To use this method in its Type-extension form, make a call like:
/// <code>
/// object Default = someType.GetDefault();
/// </code>
/// </example>
/// <seealso cref="GetDefault<T>"/>
public static object GetDefault(this Type type)
{
// If no Type was supplied, if the Type was a reference type, or if the Type was a System.Void, return null
if (type == null || !type.IsValueType || type == typeof(void))
return null;
// If the supplied Type has generic parameters, its default value cannot be determined
if (type.ContainsGenericParameters)
throw new ArgumentException(
"{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe supplied value type <" + type +
"> contains generic parameters, so the default value cannot be retrieved");
// If the Type is a primitive type, or if it is another publicly-visible value type (i.e. struct/enum), return a
// default instance of the value type
if (type.IsPrimitive || !type.IsNotPublic)
{
try
{
return Activator.CreateInstance(type);
}
catch (Exception e)
{
throw new ArgumentException(
"{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe Activator.CreateInstance method could not " +
"create a default instance of the supplied value type <" + type +
"> (Inner Exception message: \"" + e.Message + "\")", e);
}
}
// Fail with exception
throw new ArgumentException("{" + MethodInfo.GetCurrentMethod() + "} Error:\n\nThe supplied value type <" + type +
"> is not a publicly-visible type, so the default value cannot be retrieved");
}
在这些示例中,GetDefault方法在静态类DefaultValue中实现。调用此方法与像声明:
object Default = DefaultValue.GetDefault(someType);
要使用GetDefault方法作为类型的扩展方法,这样称呼它:
object Default = someType.GetDefault();
这第二个,类型扩展方法是一个简单的客户端代码语法,因为它不需要在调用中引用包含DefaultValue类限定符。
GetDefault的上述运行时形式的工作原理与C#“default”关键字的相同语义相同,并产生相同的结果。
要使用GetDefault的通用形式,您可以访问以下功能:
/// <summary>
/// [ <c>public static T GetDefault< T >()</c> ]
/// <para></para>
/// Retrieves the default value for a given Type
/// </summary>
/// <typeparam name="T">The Type for which to get the default value</typeparam>
/// <returns>The default value for Type T</returns>
/// <remarks>
/// If a reference Type or a System.Void Type is supplied, this method always returns null. If a value type
/// is supplied which is not publicly visible or which contains generic parameters, this method will fail with an
/// exception.
/// </remarks>
/// <seealso cref="GetDefault(Type)"/>
public static T GetDefault<T>()
{
return (T) GetDefault(typeof(T));
}
的一般形式的呼叫可以是这样的:
int? inDefaultVal = DefaultValue.GetDefault<int?>();
当然,上述通用GetDefault的形式对于C#来说是不必要的,因为它和默认的(T)一样。它仅适用于不支持“默认”关键字但支持泛型类型的.NET语言。在大多数情况下,通用形式是不必要的。
有用的推论方法是确定某个对象是否包含其Type类型的默认值的方法。我还依赖以下IsObjectSetToDefault方法用于该目的:
/// <summary>
/// [ <c>public static bool IsObjectSetToDefault(this Type ObjectType, object ObjectValue)</c> ]
/// <para></para>
/// Reports whether a value of type T (or a null reference of type T) contains the default value for that Type
/// </summary>
/// <remarks>
/// Reports whether the object is empty or unitialized for a reference type or nullable value type (i.e. is null) or
/// whether the object contains a default value for a non-nullable value type (i.e. int = 0, bool = false, etc.)
/// <para></para>
/// NOTE: For non-nullable value types, this method introduces a boxing/unboxing performance penalty.
/// </remarks>
/// <param name="ObjectType">Type of the object to test</param>
/// <param name="ObjectValue">The object value to test, or null for a reference Type or nullable value Type</param>
/// <returns>
/// true = The object contains the default value for its Type.
/// <para></para>
/// false = The object has been changed from its default value.
/// </returns>
public static bool IsObjectSetToDefault(this Type ObjectType, object ObjectValue)
{
// If no ObjectType was supplied, attempt to determine from ObjectValue
if (ObjectType == null)
{
// If no ObjectValue was supplied, abort
if (ObjectValue == null)
{
MethodBase currmethod = MethodInfo.GetCurrentMethod();
string ExceptionMsgPrefix = currmethod.DeclaringType + " {" + currmethod + "} Error:\n\n";
throw new ArgumentNullException(ExceptionMsgPrefix + "Cannot determine the ObjectType from a null Value");
}
// Determine ObjectType from ObjectValue
ObjectType = ObjectValue.GetType();
}
// Get the default value of type ObjectType
object Default = ObjectType.GetDefault();
// If a non-null ObjectValue was supplied, compare Value with its default value and return the result
if (ObjectValue != null)
return ObjectValue.Equals(Default);
// Since a null ObjectValue was supplied, report whether its default value is null
return Default == null;
}
上面IsObjectSetToDefault
方法既可以在其天然形式被称为或作为型类扩展访问。
你能解释它为什么不起作用吗?有错误吗?它只是没有回报你所期望的? – Gabe 2010-03-22 06:34:41
@Josh,谢谢!你喜欢它。 – viky 2010-03-22 06:48:59
@gabe,它适用于类型名称,但不适用于该类型名称的Type实例,我的意思是默认(Decimal)有效,但默认(typeof(Decimal))不会 – viky 2010-03-22 07:19:40