如何通过FieldInfo.GetValue()得到Nullable <t>(而不是基础值)?</t>

时间:2011-11-22 01:19:57

标签: c# reflection nullable system.reflection

在一个应用程序中,我有一些代码具有Nullable&lt; int&gt;的FieldInfo。我需要检索可以为空的值(而不是基础值),如下面的示例所示:

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 )而不是可空(在此示例中为Nullable&lt; int&gt;)。 / p>

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

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:3)

在这种情况下,v的类型为object。如果value为null,则v将为null;如果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属性的对象;如果没有,你就会得到价值。

答案 1 :(得分:0)

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

如果您有多个可空类型,那么您可以通过“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];
                }
            }
        }
    }

}