C# 反射:如何获取 Nullable<int> 的类型?

Posted

技术标签:

【中文标题】C# 反射:如何获取 Nullable<int> 的类型?【英文标题】:C# Reflection: How to get the type of a Nullable<int>? 【发布时间】:2012-01-22 22:14:34 【问题描述】:

我想做的是这样的:

switch( myObject.GetType().GetProperty( "id") )

    case ??: 
        // when Nullable<Int32>, do this
    case ??:
        // when string, do this
    case ??:
        // when Nullable<bool>, do this

object.GetType() 下的哪个路径将包含我可以使用 case 语句比较的数据类型的字符串名称?我需要知道类型,这样我才能拥有许多 Convert.ToInt32( string ) 之一,它将使用反射设置 myObject 的值。

【问题讨论】:

这几乎肯定是做错了。为什么不能利用多态性,而不是使用巨大的 switch 语句? 如果您建议创建多个具有不同参数类型的函数,我可以。在这种情况下,我将一组不同类型的属性从一个对象复制到另一个对象,其中一个对象始终是字符串类型。所以,我需要转换值来分配它。我对反射的经验很少。 @CodyGray 他可能正在做一些关于反射的事情,比如编写自己的 ORM。或者为所有这些 DAO 编写自定义序列化程序,你永远不会知道。 这就是为什么它是“几乎肯定”,而不是“肯定”。即使他正在做这些事情,也有争论为什么这些也是错误的。关于为什么 ORM 是一个糟糕的数据库模式已经写了很多,我看不出有什么令人信服的理由说明你不能编写一个使用多态类型的序列化程序。评论的目的是让 Zim 博士思考这是否真的是最好的选择,这就是为什么它是评论而不是答案。 @nawfal @CodyGray 我明白你关于caution 的观点,虽然表达你的观点,但那里的“确定”感觉像是一个强有力的词。我不相信 ORM 很差(恰恰相反),并且可以看到自定义序列化实现在哪里需要这个。前几天我正在编写一个用于同步来自两个不同来源的数据的同步框架,如果你需要它快速而肮脏的话,我花更少的时间来思考成员,而不是去实现项目中所有类型的接口。沿着这些思路......当约定优于配置时......等等。到处都是 Shoehorning OOP 是一个坏主意。 【参考方案1】:

更新:看起来 C# 7 将支持打开Types,因为这个问题的提问者试图这样做。虽然有点不同,所以要小心语法地雷。

你不需要一个字符串名称来比较它:

if (myObject.GetType().GetProperty("id").PropertyType == typeof(Nullable<Int32>))
    // when Nullable<Int32>, do this
else if (myObject.GetType().GetProperty("id").PropertyType == typeof(string))
    // when string, do this
else if (myObject.GetType().GetProperty("id").PropertyType == typeof(Nullable<bool>))
    // when Nullable<bool>, do this

【讨论】:

您确定将 .GetType() 与 typeof(Nullable) 进行比较还是 GetType() 下的属性?假设 int?和 Nullable 是同一类型,a.GetType() != typeof( Nullable). 就像 Eric 说的,没有装箱的Nullable&lt;T&gt;。如果 Nullables 不为 null,则将它们装箱为基础类型,或者 null,如果它们是无类型的。因此,您的代码将无法正常工作。 这个结构存在。但是GetType() 永远不会返回Nullable&lt;T&gt;,因为GetType() 对装箱值进行操作,并且可为空的值不会被装箱为Nullable&lt;T&gt;。因此,您的示例中的第一个和第三个if 将永远不会满足。 他在 myObject.GetType().GetProperty("ID").PropertyType 工作。属性的静态类型可以是Nullable&lt;T&gt;,只是GetType()不能返回nullable。 更正的答案为时已晚,无法帮助提问者,但人们不断来到这里,希望它能帮助其他人。【参考方案2】:

正如@Cody Gray 所说,if 语句可能是最好的方法

var t = myObject.GetType();

if (t == typeof(Nullable<int>))
 
else if (t == typeof(string))

else if (t==typeof(Nullable<bool>))

【讨论】:

有趣的是,当int? a = 3 然后typeof( a) 是“System.Int32” @Dr.Zim:请看这里的解释:***.com/questions/785358/… @Dr.Zim typeof(a) 甚至无法编译。返回int的是a.GetType() 错误答案。如果myObject.GetType 被声明为intint?myObject.GetType 将始终给出int【参考方案3】:

我一直在使用以下类型的代码来检查类型是否可为空并获取实际类型:

if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))

    return Nullable.GetUnderlyingType(type);

如果类型是例如可空此代码返回 int 部分(基础类型)。如果您只是需要将对象转换为特定类型,您可以使用System.Convert.ChangeType 方法。

【讨论】:

+1 值得注意的是,此方法在内部执行相同的检查,如果给定类型不是 typeof(Nullable&lt;&gt;),则返回 null,因此之后进行 null 检查而不是 if 语句也可以。【参考方案4】:

这个问题非常令人困惑。 “myObject”是可能是可为空的 int 的对象吗?还是属性“id”可能是可为空的 int 类型?

如果是前者,则无法回答您的问题,因为它以虚假为前提。没有盒装的可为空的 int 之类的东西。我注意到所有提出if (myobject.GetType() == typeof(int?)) 的答案都是不正确的;条件永远不会成立。

当您将一个可为空的 int 转换为对象时,它要么变成一个空引用(如果可为空的 int 没有值),要么它变成一个装箱的 int。无法确定对象是否包含可为空的 int,因为对象从不包含可为空的 int。

如果是后者,请将 属性类型typeof(int?) 进行比较。您不能使用开关;开关情况只能使用常量,类型不是常量。

话虽如此,这是一种糟糕的代码气味。你为什么首先使用反射?

【讨论】:

更新:在 C# 7 中,switch 语句不再需要常量表达式 :) 并提供一种切换类型的机制。该功能于 2001 年首次提出?我想。所以,16 年,还不错。 “类型不是常量” 我原以为类型会是常量,因为它们在运行时很难更改(无 DLR)。这可能解释(或证明/证明)所有 string 类型被更改为 ReadOnlySpan&lt;char&gt; =/【参考方案5】:

在 .net 中,值类型的实例只是位的集合,没有关联的类型信息。然而,对于Nullable&lt;T&gt; 以外的每个值类型,系统也会自动生成一个对应的类类型,该类类型派生自System.ValueType。存在从值类型到自动生成的类类型的扩大转换,以及从自动生成的类类型到值类型的缩小转换。在Nullable&lt;T&gt; 的情况下,没有对应的自动生成的类类型与值类型之间的转换;相反,在Nullable&lt;T&gt; 和与T 关联的类类型之间存在双向扩展转换。

据我所知,这种奇怪的行为是为了让 null 和空的 Nullable&lt;T&gt; 之间的比较返回 true。

【讨论】:

以上是关于C# 反射:如何获取 Nullable<int> 的类型?的主要内容,如果未能解决你的问题,请参考以下文章

Nullable-如何在 C# 中的 DateTime 类型中仅比较没有时间的日期?

c# 如何通过反射 获取属性值

C#反射执行方法返回List,怎么获取List

C#通过反射进行枚举描述相关操作

C# 反射和获取属性

如何更改通过反射 C# 获取的属性值