C# 如何检查对象是否可为空?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/374651/
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
How to check if an object is nullable?
提问by Autodidact
How do I check if a given object is nullable in other words how to implement the following method...
如何检查给定对象是否可为空,换句话说,如何实现以下方法...
bool IsNullableValueType(object o)
{
...
}
EDIT: I am looking for nullable value types. I didn't have ref types in mind.
编辑:我正在寻找可为空的值类型。我没有想到 ref 类型。
//Note: This is just a sample. The code has been simplified
//to fit in a post.
public class BoolContainer
{
bool? myBool = true;
}
var bc = new BoolContainer();
const BindingFlags bindingFlags = BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Instance
;
object obj;
object o = (object)bc;
foreach (var fieldInfo in o.GetType().GetFields(bindingFlags))
{
obj = (object)fieldInfo.GetValue(o);
}
obj now refers to an object of type bool
(System.Boolean
) with value equal to true
. What I really wanted was an object of type Nullable<bool>
obj 现在引用类型为bool
( System.Boolean
)的对象,其值等于true
。我真正想要的是一个类型的对象Nullable<bool>
So now as a work around I decided to check if o is nullable and create a nullable wrapper around obj.
所以现在作为一种解决方法,我决定检查 o 是否可以为空并围绕 obj 创建一个可为空的包装器。
采纳答案by Marc Gravell
There are two types of nullable - Nullable<T>
and reference-type.
有两种类型的可为空 -Nullable<T>
和引用类型。
Jon has corrected me that it is hard to get type if boxed, but you can with generics:
- so how about below. This is actually testing type T
, but using the obj
parameter purely for generic type inference (to make it easy to call) - it would work almost identically without the obj
param, though.
Jon 纠正了我,如果装箱很难获得类型,但你可以使用泛型: - 那么下面怎么样。这实际上是在测试 type T
,但将obj
参数纯粹用于泛型类型推断(以使其易于调用)-obj
尽管没有参数,它的工作方式几乎相同。
static bool IsNullable<T>(T obj)
{
if (obj == null) return true; // obvious
Type type = typeof(T);
if (!type.IsValueType) return true; // ref-type
if (Nullable.GetUnderlyingType(type) != null) return true; // Nullable<T>
return false; // value-type
}
But this won't work so well if you have already boxed the value to an object variable.
但是,如果您已经将值装箱到对象变量中,这将不会奏效。
Microsoft documentation: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/how-to-identify-a-nullable-type
微软文档:https: //docs.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/how-to-identify-a-nullable-type
回答by Jon Skeet
Well, you could use:
那么,你可以使用:
return !(o is ValueType);
... but an object itself isn't nullable or otherwise - a typeis. How were you planning on using this?
...但对象本身不可为空或以其他方式 -类型是。你打算怎么用这个?
回答by thinkbeforecoding
Be carefull, when boxing a nullable type (Nullable<int>
or int? for instance) :
小心,在装箱可空类型(Nullable<int>
或 int?例如)时:
int? nullValue = null;
object boxedNullValue = (object)nullValue;
Debug.Assert(boxedNullValue == null);
int? value = 10;
object boxedValue = (object)value;
Debug.Assert( boxedValue.GetType() == typeof(int))
It becomes a true reference type, so you lose the fact it was nullable.
它变成了一个真正的引用类型,所以你失去了它可以为空的事实。
回答by Dean Chalk
There is a very simple solution using method overloads
使用方法重载有一个非常简单的解决方案
http://deanchalk.com/is-it-nullable/
http://deanchalk.com/is-it-nullable/
excerpt:
摘抄:
public static class ValueTypeHelper
{
public static bool IsNullable<T>(T t) { return false; }
public static bool IsNullable<T>(T? t) where T : struct { return true; }
}
then
然后
static void Main(string[] args)
{
int a = 123;
int? b = null;
object c = new object();
object d = null;
int? e = 456;
var f = (int?)789;
bool result1 = ValueTypeHelper.IsNullable(a); // false
bool result2 = ValueTypeHelper.IsNullable(b); // true
bool result3 = ValueTypeHelper.IsNullable(c); // false
bool result4 = ValueTypeHelper.IsNullable(d); // false
bool result5 = ValueTypeHelper.IsNullable(e); // true
bool result6 = ValueTypeHelper.IsNullable(f); // true
回答by Allon Guralnek
The question of "How to check if a type is nullable?" is actually "How to check if a type is Nullable<>
?", which can be generalized to "How to check if a type is a constructed type of some generic type?", so that it not only answers the question "Is Nullable<int>
a Nullable<>
?", but also "Is List<int>
a List<>
?".
“如何检查类型是否可为空?”的问题 实际上是“如何检查一个类型是否是Nullable<>
?”,可以概括为“如何检查一个类型是否是某个泛型类型的构造类型?”,这样它不仅可以回答“是Nullable<int>
一个Nullable<>
?”的问题,而且还“是List<int>
一个List<>
?”。
Most of the provided solution use the Nullable.GetUnderlyingType()
method, which will obviously only work with the case of Nullable<>
. I did not see the general reflective solution that will work with any generic type, so I decided to add it here for posterity, even though this question has already been answered long ago.
大多数提供的解决方案都使用该Nullable.GetUnderlyingType()
方法,这显然只适用于Nullable<>
. 我没有看到适用于任何泛型类型的通用反射解决方案,所以我决定将它添加到这里以供后代使用,即使这个问题很久以前就已经得到了回答。
To check if a type is some form of Nullable<>
using reflection, you first have to convert your constructed generic type, for example Nullable<int>
, into the generic type definition, Nullable<>
. You can do that by using the GetGenericTypeDefinition()
method of the Type
class. You can then compare the resulting type to Nullable<>
:
要检查类型是否是Nullable<>
使用反射的某种形式,首先必须将构造的泛型类型(例如Nullable<int>
)转换为泛型类型定义Nullable<>
。您可以通过使用类的GetGenericTypeDefinition()
方法来做到这一点Type
。然后,您可以将结果类型与Nullable<>
:
Type typeToTest = typeof(Nullable<int>);
bool isNullable = typeToTest.GetGenericTypeDefinition() == typeof(Nullable<>);
// isNullable == true
The same can be applied to any generic type:
这同样适用于任何泛型类型:
Type typeToTest = typeof(List<int>);
bool isList = typeToTest.GetGenericTypeDefinition() == typeof(List<>);
// isList == true
Several types may seem the same, but a different number of type arguments means it's a completely different type.
几种类型可能看起来相同,但不同数量的类型参数意味着它是一种完全不同的类型。
Type typeToTest = typeof(Action<DateTime, float>);
bool isAction1 = typeToTest.GetGenericTypeDefinition() == typeof(Action<>);
bool isAction2 = typeToTest.GetGenericTypeDefinition() == typeof(Action<,>);
bool isAction3 = typeToTest.GetGenericTypeDefinition() == typeof(Action<,,>);
// isAction1 == false
// isAction2 == true
// isAction3 == false
Since Type
object are instantiated once per type, you can check for reference equality between them. So if you want to check if two objects are of the same generic type definition, you can write:
由于Type
每个类型都实例化对象一次,因此您可以检查它们之间的引用相等性。因此,如果要检查两个对象是否具有相同的泛型类型定义,可以编写:
var listOfInts = new List<int>();
var listOfStrings = new List<string>();
bool areSameGenericType =
listOfInts.GetType().GetGenericTypeDefinition() ==
listOfStrings.GetType().GetGenericTypeDefinition();
// areSameGenericType == true
If you'd like to check if an object is nullable, rather than a Type
, then you can use the above technique together with Marc Gravell's solution to create a rather simple method:
如果您想检查一个对象是否可以为空,而不是 a Type
,那么您可以将上述技术与 Marc Gravell 的解决方案一起使用来创建一个相当简单的方法:
static bool IsNullable<T>(T obj)
{
if (!typeof(T).IsGenericType)
return false;
return typeof(T).GetGenericTypeDefinition() == typeof(Nullable<>);
}
回答by Mark Jones
There are two issues here: 1) testing to see whether a Type is nullable; and 2) testing to see whether an object represents a nullable Type.
这里有两个问题:1)测试一个类型是否可以为空;和 2) 测试以查看对象是否表示可为空的类型。
For issue 1 (testing a Type), here's a solution I've used in my own systems: TypeIsNullable-check solution
对于问题 1(测试类型),这是我在自己的系统中使用的解决方案:TypeIsNullable-check 解决方案
For issue 2 (testing an object), Dean Chalk's solution above works for value types, but it doesn't work for reference types, since using the <T> overload always returns false. Since reference types are inherently nullable, testing a reference type should always return true. Please see the note [About "nullability"] below for an explanation of these semantics. Thus, here's my modification to Dean's approach:
对于问题 2(测试对象),上面的 Dean Chalk 的解决方案适用于值类型,但不适用于引用类型,因为使用 <T> 重载总是返回 false。由于引用类型本质上是可为空的,因此测试引用类型应始终返回 true。有关这些语义的解释,请参阅下面的注释 [关于“可空性”]。因此,这是我对 Dean 方法的修改:
public static bool IsObjectNullable<T>(T obj)
{
// If the parameter-Type is a reference type, or if the parameter is null, then the object is always nullable
if (!typeof(T).IsValueType || obj == null)
return true;
// Since the object passed is a ValueType, and it is not null, it cannot be a nullable object
return false;
}
public static bool IsObjectNullable<T>(T? obj) where T : struct
{
// Always return true, since the object-type passed is guaranteed by the compiler to always be nullable
return true;
}
And here's my modification to the client-test code for the above solution:
这是我对上述解决方案的客户端测试代码的修改:
int a = 123;
int? b = null;
object c = new object();
object d = null;
int? e = 456;
var f = (int?)789;
string g = "something";
bool isnullable = IsObjectNullable(a); // false
isnullable = IsObjectNullable(b); // true
isnullable = IsObjectNullable(c); // true
isnullable = IsObjectNullable(d); // true
isnullable = IsObjectNullable(e); // true
isnullable = IsObjectNullable(f); // true
isnullable = IsObjectNullable(g); // true
The reason I've modified Dean's approach in IsObjectNullable<T>(T t) is that his original approach always returned false for a reference type. Since a method like IsObjectNullable should be able to handle reference-type values and since all reference types are inherently nullable, then if either a reference type or a null is passed, the method should always return true.
我在 IsObjectNullable<T>(T t) 中修改 Dean 的方法的原因是他的原始方法对于引用类型总是返回 false。由于像 IsObjectNullable 这样的方法应该能够处理引用类型的值,并且由于所有引用类型本质上都是可为空的,因此如果传递了引用类型或 null,则该方法应始终返回 true。
The above two methods could be replaced with the following single method and achieve the same output:
以上两种方法可以替换为以下单一方法并实现相同的输出:
public static bool IsObjectNullable<T>(T obj)
{
Type argType = typeof(T);
if (!argType.IsValueType || obj == null)
return true;
return argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(Nullable<>);
}
However, the problem with this last, single-method approach is that performance suffers when a Nullable<T> parameter is used. It takes much more processor time to execute the last line of this single method than it does to allow the compiler to choose the second method overload shown previously when a Nullable<T>-type parameter is used in the IsObjectNullable call. Therefore, the optimum solution is to use the two-method approach illustrated here.
然而,最后一种单一方法的问题在于,当使用 Nullable<T> 参数时,性能会受到影响。与在 IsObjectNullable 调用中使用 Nullable<T> 类型参数时允许编译器选择前面显示的第二个方法重载相比,执行此单个方法的最后一行所需的处理器时间要多得多。因此,最佳解决方案是使用此处说明的两种方法。
CAVEAT: This method works reliably only if called using the original object reference or an exact copy, as shown in the examples. However, if a nullable object is boxed to another Type (such as object, etc.) instead of remaining in its original Nullable<> form, this method will not work reliably. If the code calling this method is not using the original, unboxed object reference or an exact copy, it cannot reliably determine the object's nullability using this method.
警告:只有在使用原始对象引用或精确副本调用时,此方法才能可靠地工作,如示例中所示。但是,如果可空对象被装箱到另一个类型(例如对象等)而不是保持其原始 Nullable<> 形式,则此方法将无法可靠地工作。如果调用此方法的代码未使用原始的、未装箱的对象引用或精确副本,则无法使用此方法可靠地确定对象的可空性。
In most coding scenarios, to determine nullability one must instead rely on testing the original object's Type, not its reference (e.g., code must have access to the object's original Type to determine nullability). In these more common cases, IsTypeNullable (see link) is a reliable method of determining nullability.
在大多数编码场景中,为了确定可空性,必须依赖于测试原始对象的类型,而不是其引用(例如,代码必须有权访问对象的原始类型才能确定可空性)。在这些更常见的情况下,IsTypeNullable(请参阅链接)是确定可空性的可靠方法。
P.S. - About "nullability"
PS - 关于“可空性”
I should repeat a statement about nullability I made in a separate post, which applies directly to properly addressing this topic. That is, I believe the focus of the discussion here should not be how to check to see if an object is a generic Nullable type, but rather whether one can assign a value of null to an object of its type. In other words, I think we should be determining whether an object type is nullable, not whether it is Nullable. The difference is in semantics, namely the practical reasons for determining nullability, which is usually all that matters.
我应该重复我在另一篇文章中所做的关于可空性的声明,它直接适用于正确解决这个主题。也就是说,我认为这里讨论的重点不应该是如何检查一个对象是否是通用的 Nullable 类型,而是是否可以为它的类型的对象分配一个 null 值。换句话说,我认为我们应该确定一个对象类型是否可以为 null,而不是它是否为 Nullable。区别在于语义,即确定可空性的实际原因,这通常是最重要的。
In a system using objects with types possibly unknown until run-time (web services, remote calls, databases, feeds, etc.), a common requirement is to determine whether a null can be assigned to the object, or whether the object might contain a null. Performing such operations on non-nullable types will likely produce errors, usually exceptions, which are very expensive both in terms of performance and coding requirements. To take the highly-preferred approach of proactively avoiding such problems, it is necessary to determine whether an object of an arbitrary Type is capable of containing a null; i.e., whether it is generally 'nullable'.
在使用类型可能在运行时之前未知的对象(Web 服务、远程调用、数据库、提要等)的系统中,一个常见的要求是确定是否可以将空值分配给对象,或者对象是否可能包含一个空值。对不可空类型执行此类操作可能会产生错误,通常是异常,这在性能和编码要求方面都非常昂贵。为了采取主动避免此类问题的首选方法,需要确定任意类型的对象是否能够包含空值;即,它是否通常是“可空的”。
In a very practical and typical sense, nullability in .NET terms does not at all necessarily imply that an object's Type is a form of Nullable. In many cases in fact, objects have reference types, can contain a null value, and thus are all nullable; none of these have a Nullable type. Therefore, for practical purposes in most scenarios, testing should be done for the general concept of nullability, vs. the implementation-dependent concept of Nullable. So we should not be hung up by focusing solely on the .NET Nullable type but rather incorporate our understanding of its requirements and behavior in the process of focusing on the general, practical concept of nullability.
在非常实际和典型的意义上,.NET 术语中的可空性并不一定意味着对象的类型是 Nullable 的一种形式。实际上很多情况下,对象都有引用类型,可以包含空值,因此都是可以为空的;这些都没有 Nullable 类型。因此,在大多数情况下,出于实际目的,应该针对可空性的一般概念进行测试,而不是 Nullable 的实现相关概念。因此,我们不应该仅仅关注 .NET Nullable 类型,而应该在关注可空性的一般实用概念的过程中结合我们对其要求和行为的理解。
回答by CARLOS LOTH
The simplest way I can figure out is:
我能想到的最简单的方法是:
public bool IsNullable(object obj)
{
Type t = obj.GetType();
return t.IsGenericType
&& t.GetGenericTypeDefinition() == typeof(Nullable<>);
}
回答by Erik
This works for me and seems simple:
这对我有用,看起来很简单:
static bool IsNullable<T>(T obj)
{
return default(T) == null;
}
For value types:
对于值类型:
static bool IsNullableValueType<T>(T obj)
{
return default(T) == null && typeof(T).BaseType != null && "ValueType".Equals(typeof(T).BaseType.Name);
}
回答by Roel van Megen
Maybe a little bit off topic, but still some interesting information. I find a lot of people that use Nullable.GetUnderlyingType() != null
to identity if a type is nullable. This obviously works, but Microsoft advices the following type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)
(see http://msdn.microsoft.com/en-us/library/ms366789.aspx).
也许有点离题,但仍然有一些有趣的信息。我发现很多人Nullable.GetUnderlyingType() != null
习惯于识别类型是否可为空。这显然有效,但 Microsoft 建议如下type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)
(参见http://msdn.microsoft.com/en-us/library/ms366789.aspx)。
I looked at this from a performance side of view. The conclusion of the test (one million attempts) below is that when a type is a nullable, the Microsoft option delivers the best performance.
我是从性能的角度来看的。下面的测试(一百万次尝试)的结论是,当类型可以为 null 时,Microsoft 选项提供最佳性能。
Nullable.GetUnderlyingType():1335ms(3 times slower)
Nullable.GetUnderlyingType():1335 毫秒(慢 3 倍)
GetGenericTypeDefinition() == typeof(Nullable<>):500ms
GetGenericTypeDefinition() == typeof(Nullable<>): 500ms
I know that we are talking about a small amount of time, but everybody loves to tweak the milliseconds :-)! So if you're boss wants you to reduce some milliseconds then this is your saviour...
我知道我们谈论的是少量时间,但每个人都喜欢调整毫秒 :-)!因此,如果您的老板希望您减少一些毫秒,那么这就是您的救星...
/// <summary>Method for testing the performance of several options to determine if a type is nullable</summary>
[TestMethod]
public void IdentityNullablePerformanceTest()
{
int attempts = 1000000;
Type nullableType = typeof(Nullable<int>);
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int attemptIndex = 0; attemptIndex < attempts; attemptIndex++)
{
Assert.IsTrue(Nullable.GetUnderlyingType(nullableType) != null, "Expected to be a nullable");
}
Console.WriteLine("Nullable.GetUnderlyingType(): {0} ms", stopwatch.ElapsedMilliseconds);
stopwatch.Restart();
for (int attemptIndex = 0; attemptIndex < attempts; attemptIndex++)
{
Assert.IsTrue(nullableType.IsGenericType && nullableType.GetGenericTypeDefinition() == typeof(Nullable<>), "Expected to be a nullable");
}
Console.WriteLine("GetGenericTypeDefinition() == typeof(Nullable<>): {0} ms", stopwatch.ElapsedMilliseconds);
stopwatch.Stop();
}
回答by VJPPaz
a simple way to do this:
一个简单的方法来做到这一点:
public static bool IsNullable(this Type type)
{
if (type.IsValueType) return Activator.CreateInstance(type) == null;
return true;
}
these are my unit tests and all passed
这些是我的单元测试并且都通过了
IsNullable_String_ShouldReturn_True
IsNullable_Boolean_ShouldReturn_False
IsNullable_Enum_ShouldReturn_Fasle
IsNullable_Nullable_ShouldReturn_True
IsNullable_Class_ShouldReturn_True
IsNullable_Decimal_ShouldReturn_False
IsNullable_Byte_ShouldReturn_False
IsNullable_KeyValuePair_ShouldReturn_False
actual unit tests
实际单元测试
[TestMethod]
public void IsNullable_String_ShouldReturn_True()
{
var typ = typeof(string);
var result = typ.IsNullable();
Assert.IsTrue(result);
}
[TestMethod]
public void IsNullable_Boolean_ShouldReturn_False()
{
var typ = typeof(bool);
var result = typ.IsNullable();
Assert.IsFalse(result);
}
[TestMethod]
public void IsNullable_Enum_ShouldReturn_Fasle()
{
var typ = typeof(System.GenericUriParserOptions);
var result = typ.IsNullable();
Assert.IsFalse(result);
}
[TestMethod]
public void IsNullable_Nullable_ShouldReturn_True()
{
var typ = typeof(Nullable<bool>);
var result = typ.IsNullable();
Assert.IsTrue(result);
}
[TestMethod]
public void IsNullable_Class_ShouldReturn_True()
{
var typ = typeof(TestPerson);
var result = typ.IsNullable();
Assert.IsTrue(result);
}
[TestMethod]
public void IsNullable_Decimal_ShouldReturn_False()
{
var typ = typeof(decimal);
var result = typ.IsNullable();
Assert.IsFalse(result);
}
[TestMethod]
public void IsNullable_Byte_ShouldReturn_False()
{
var typ = typeof(byte);
var result = typ.IsNullable();
Assert.IsFalse(result);
}
[TestMethod]
public void IsNullable_KeyValuePair_ShouldReturn_False()
{
var typ = typeof(KeyValuePair<string, string>);
var result = typ.IsNullable();
Assert.IsFalse(result);
}