Как получить Nullable <T>(вместо базового значения) через FieldInfo.GetValue ()? - PullRequest
1 голос
/ 22 ноября 2011

В приложении у меня есть некоторый код, который имеет FieldInfo для Nullable , и мне нужно извлечь значение Nullable (не базовое значение), как в примере ниже:

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 (в этом примере Nullable ).

PS: реальное приложение не имеет типа nullable во время компиляции, поэтому приведение невозможно.

Заранее спасибо за любую помощь.

Ответы [ 2 ]

3 голосов
/ 22 ноября 2011

В этом случае 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 голосов
/ 23 ноября 2011

Для начала нужно получить все свойства класса «Тест» в массиве объектов PropertyInfo.Сформируйте цикл и вызовите метод GetGenericTypeDefinition свойства PropertyType каждого PropertyInfo и сравните его с типом Nullable.Также проверьте, если это универсальный тип.Если оба имеют значение true, тогда вызовите метод «GetGenericArguments» свойства «PropertyType» этого PropertyInfo.Это возвращает массив объектов «Тип».Возьми свой первый элемент.Это будет ваш требуемый тип.

Если у вас есть несколько обнуляемых типов, вы можете получить имя свойства с помощью «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];
                }
            }
        }
    }

}
...