2011-11-22 125 views
1

在应用程序中我有了一个字段信息可空<INT>一些代码,我需要像波纹管样品中检索空值(而不是基础值):如何通过FieldInfo.GetValue()获得可空的<T>(而不是基础值)?

class Test 
{ 
    public int? value; 
} 

public class Program 
{ 
    static void Main(string[] args) 
    { 
     var obj = new Test { value = 10 }; 
     var fld = typeof (Test).GetField("value"); 
     var v = fld.GetValue(obj); 

     System.Diagnostics.Debug.WriteLine(v.GetType().FullName); 
     System.Diagnostics.Debug.WriteLine(fld.FieldType.FullName); 
    } 
} 

我的问题是, v始终指定底层值(在此示例中为int),而不是可空(在此示例中为可空的<int>)。

PS:真正的应用程序在编译时没有可为空的类型,所以无法进行强制转换。

在此先感谢您的帮助。

+1

这就是当你将一个'可为空'时发生的情况。你可以将对象解除“int”或“int?',但不是没有强制转换。 – dtb

+0

@dtb我明白,当拳击空行时运行时将实际上框的基础价值。但是当我调用fld.GetValue(obj)时,唯一的拳击操作发生了。我期望FieldInfo有这个方法的一个通用版本(所以我可以完全避免装箱),或者运行时会以不同的方式处理(以相同的方式,它对拳击的处理方式不同) – Vagaus

回答

3

在这种情况下,v的类型为object。如果value为空,则v将为空;如果value是某个整数,那么v将是该整数。如果你想v实际上有类型Nullable<int>那么你必须声明它:var v = (int?) fld.GetValue(obj);

如果您需要能够参考v.Value并获取装箱值,则可能需要记录fld为空(Nullable.GetUnderlyingType(fld.FieldType) != null)的事实。请注意,泛型不会帮助您,因为您在编译时不知道T

这里是你可以使用一个帮手:

struct NullableObject 
{ 
    public object Value { get; private set; } 

    public static object GetField(object Target, FieldInfo Field) 
    { 
     object value = Field.GetValue(Target); 
     if (Nullable.GetUnderlyingType(Field.FieldType) != null) 
      return new NullableObject { Value = value }; 
     return value; 
    } 
} 

public static class NullableHelper 
{ 
    public static object GetNullableValue(this FieldInfo field, object target) 
    { 
     return NullableObject.GetField(target, field); 
    } 
} 

然后,而不是调用var v = fld.GetValue(obj);,说var v = fld.GetNullableValue(obj);。如果fld表示一个Nullable类型,您将得到一个具有Value属性的对象;如果没有,你只会得到价值。

+0

感谢您的答案,但作为我说过,因为在编译时我不知道确切的类型,所以不可能进行转换。 – Vagaus

+0

@Vagaus:“框”包含值或null;它不记录'Nullable <>'方面。为什么你需要知道原始类型是什么? – Gabe

+0

我的应用程序访问表达式树试图解析表达式,如:** a.b.Value **。在访问它时记录a.b值(使用FieldInfo.GetValue(a))。在这一点上,我预计会返回一个可为空的,因为** b **是空的。后面的代码使用FieldInfo.GetValue(a)的结果作为PropertyInfo.GetValue()(但是这次使用“Value”属性)的输入做同样的事情。此时它失败,因为FieldInfo.GetValue(a)返回的是底层值而不是可为空值,并且“Numlable <>”结构中声明了“Value”属性。 – Vagaus

0

首先,您需要在PropertyInfo对象数组中获取“Test”类的所有属性。形成一个循环,并调用每个PropertyInfo的“PropertyType”属性的“GetGenericTypeDefinition”方法,并将其与Nullable类型进行比较。同时检查它是否是泛型类型。如果两者都为真,则调用该PropertyInfo的“PropertyType”属性的“GetGenericArguments”方法。这将返回“类型”对象的数组。采取它的第一个元素。这将是您需要的类型。

如果您有多个可为空的类型,那么您可以通过“PropertyInfo.Name”获取该属性的名称并相应地进行比较。

以下是您可以根据自己的便利进行尝试和修改的代码。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 

namespace Nullable_Demo 
{ 
    class Test 
    { 
     public int? value { get; set; } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var obj = new Test { value = 10 }; 
      //var fld = typeof(Test).GetField("value"); 
      //var v = fld.GetValue(obj); 

      Type typeobjs = obj.GetType(); 
      PropertyInfo[] piObjs = typeobjs.GetProperties(); 

      foreach (PropertyInfo piObj in piObjs) 
      { 
       Type typeDefinedInNullable; 

       // Test for Nullable 
       bool isNullable = piObj.PropertyType.IsGenericType && 
        piObj.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>); 

       if (isNullable) 
       { 
        // Returns the basic data type without reference to Nullable (for example, System.Int32) 
        typeDefinedInNullable = piObj.PropertyType.GetGenericArguments()[0]; 
       } 
      } 
     } 
    } 

} 
相关问题