【问题标题】:Type checking on Nullable<int>对 Nullable<int> 进行类型检查
【发布时间】:2013-08-27 17:11:21
【问题描述】:

如果有以下方法:

static void DoSomethingWithTwoNullables(Nullable<int> a, Nullable<int> b)
{
    Console.WriteLine("Param a is Nullable<int>: " + (a is Nullable<int>));
    Console.WriteLine("Param a is int          : " + (a is int));
    Console.WriteLine("Param b is Nullable<int>: " + (b is Nullable<int>));
    Console.WriteLine("Param b is int          : " + (b is int));
}

当我使用 null 作为参数调用此方法时,类型检查会为此参数返回 false。例如这段代码

DoSomethingWithTwoNullables(5, new Nullable<int>());

结果如下:

Param a is Nullable<int>: True
Param a is int          : True
Param b is Nullable<int>: False
Param b is int          : False

在使用 Nullable 并传递 null 时,有什么方法可以保留类型信息?我知道在这个例子中检查类型是没有用的,但它说明了问题。在我的项目中,我将参数传递给另一个方法,该方法采用params object[] 数组并尝试识别对象的类型。这个方法需要对Nullable&lt;int&gt;Nullable&lt;long&gt;做不同的事情。

【问题讨论】:

    标签: c#


    【解决方案1】:

    直奔根本问题,不,你不能这样做。空Nullable&lt;int&gt; 与空Nullable&lt;long&gt; 具有完全相同的盒装表示,或者实际上是“正常”空。没有办法知道它是什么类型的 null,因为它的底层表示只是全零。详情请见Boxing Nullable Types

    【讨论】:

    • 因为 b 首先被装箱到 int? 导致空引用。
    • 大概你可以尝试 { } catch { } 来测试它,所以有办法找出来。我敢打赌,使用反射你可以更进一步并完善它。也许初始化一个新实例,它应该给它一个默认值,然后做typeof(variable.value)
    • @SLC:你不能。它只是一个没有类型信息的空引用。
    • @SLC 我从未见过比这更好的解释,来自微软开发部门的副总裁(我不记得他写这篇文章时的头衔是什么):blogs.msdn.com/b/somasegar/archive/2005/08/11/450640.aspx
    • 实际上,没有底层表示,就像(string)null(object)null 的底层表示一样。
    【解决方案2】:

    从概念上讲,new Nullable&lt;int&gt; null

    如果我们一概而论,忘记Nullable&lt;T&gt;

    string s = null;
    bool b = s is string;
    

    我们得到falsefalse 是对null 值进行类型检查的预期值。

    【讨论】:

    • 如果他做了b = 3;怎么办?如果它是一个字符串,那么你会得到一个错误,但如果它是一个 int 或可为空的 int 你不会得到一个错误?
    【解决方案3】:

    您可以尝试使用反射来实现这一点。 Relevant article here.

    【讨论】:

    • 你不能使用反射。在空引用上调用GetType() 将抛出NullReferenceException。没有与空引用关联的类型。链接的文章基于类型而不是对对象的引用(在这种情况下可能为空)。
    【解决方案4】:

    不幸的是,null 没有指向任何特定的内存位置,因此没有可以与之关联的元数据来查找类型。因此,您无法获得有关该变量的任何其他信息。

    【讨论】:

      【解决方案5】:

      除非我误解了这个问题,否则您可以使用GetType() 获取类型。例如,

      int? myNullableInt = null;
      Console.WriteLine(myNullableInt.GetValueOrDefault().GetType());
      

      如果myNullableInt 为空,则返回默认值。检查此返回值的类型,在这种情况下,它将返回System.Int32。您可以对返回的类型进行If..else/Switch 检查以执行相关操作。

      int?Nullable&lt;int&gt;相同)

      【讨论】:

      • 或者你可以打电话给Nullable.GetUnderlyingType()
      • 或者那个。无论哪种方式,似乎都可以获得此问题所需的信息。
      • 问题是我不知道给定的对象是否为 Nullable。它也可以是一个字符串或一个普通的 int。我想我可以使用类型检查来获取这些信息。但情况似乎并非如此。
      • @bernd_rausch 也许这个答案可能会有所帮助stackoverflow.com/a/374663/187697 如果它返回true,请继续我帖子中的代码,否则假设它不可为空并进行正常的类型检查。
      【解决方案6】:

      您不能这样做,也不应该这样做。由于Nullable&lt;T&gt; 是一个结构体,这种类型的值类型变量拥有编译时所需的所有类型信息。只需使用typeof 运算符即可。

      另一方面,您可能有一个 Nullable 实例,您在编译时不知道其类型。那必须是一个静态类型为object 或其他引用类型的变量。但是,因为 Nullable&lt;T&gt; 值将框到框 T 值中,所以 没有像框 Nullable&lt;T&gt; 这样的东西。 您检查的实例的类型将只是 T

      这就是is intis Nullable&lt;int&gt; 得到相同结果的原因。没有办法区分盒装的int 和盒装的int?,因为没有盒装的int?

      详情请见Nulls not missing anymore

      【讨论】:

        【解决方案7】:

        正如已经指出的那样,null 没有类型。要确定某个东西是int? 还是long?,您需要使用反射来获取有关存储类型的信息。下面是一些代码,您可能可以将其用作灵感(不确切知道您尝试实现的代码有点奇怪):

        class Pair<T> where T : struct {
        
          public Pair(T? a, T? b) {
            A = a;
            B = b;
          }
        
          public T? A { get; private set; }
        
          public T? B { get; private set; }
        
        }
        
        void DoSomething<T>(Pair<T> pair) where T : struct {
          DoMore(pair);
        }
        
        void DoMore(params object[] args) {
          Console.WriteLine("Do more");
          var nullableIntPairs = args.Where(IsNullableIntPair);
          foreach (Pair<int> pair in nullableIntPairs) {
            Console.WriteLine(pair.A);
            Console.WriteLine(pair.B);
          }
        }
        
        bool IsNullableIntPair(object arg) {
          var type = arg.GetType();
          return type.IsGenericType
            && type.GetGenericTypeDefinition() == typeof(Pair<>)
            && type.GetGenericArguments()[0] == typeof(int);
        }
        

        如果执行以下代码

        DoSomething(new Pair<int>(5, new int?()));
        DoSomething(new Pair<long>(new long?(), 6L));
        

        你会得到以下输出:

        多做 5 无效的 多做

        【讨论】:

          【解决方案8】:

          你可以使用 typeof :

          a == typeof(Nullable<int>) //true
          a == typeof(int) //false
          

          【讨论】:

            猜你喜欢
            • 2017-11-05
            • 2018-05-19
            • 1970-01-01
            • 2020-03-17
            • 2012-10-16
            • 1970-01-01
            • 2017-11-29
            • 2019-12-26
            • 1970-01-01
            相关资源
            最近更新 更多