Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/330.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何通过反射代码(c#)设置可空类型?_C#_Reflection - Fatal编程技术网

如何通过反射代码(c#)设置可空类型?

如何通过反射代码(c#)设置可空类型?,c#,reflection,C#,Reflection,我需要使用反射设置类的属性 我有一个字典,里面有属性名和字符串值 在反射循环中,我需要将字符串值转换为适当的属性类型,同时为每个属性设置值。其中一些属性类型是可为空的类型 如何从PropertyInfo知道属性是否为可空类型 如何使用反射设置可为null的类型 编辑: 本博客评论中定义的第一种方法似乎也起到了同样的作用: 检查可空类型很容易,int?实际上是System.Nullable。 因此,您只需检查该类型是否是System.Nullable的泛型实例。 设置不应该有区别,nullable

我需要使用反射设置类的属性

我有一个
字典
,里面有属性名和字符串值

在反射循环中,我需要将字符串值转换为适当的属性类型,同时为每个属性设置值。其中一些属性类型是可为空的类型

  • 如何从PropertyInfo知道属性是否为可空类型
  • 如何使用反射设置可为null的类型
  • 编辑: 本博客评论中定义的第一种方法似乎也起到了同样的作用:
    检查可空类型很容易,int?实际上是
    System.Nullable
    。 因此,您只需检查该类型是否是
    System.Nullable
    的泛型实例。 设置不应该有区别,
    nullableProperty.SetValue(实例,null)
    nullableProperty.SetValue(实例,3)

  • 一种方法是:

    type.GetGenericTypeDefinition() == typeof(Nullable<>)
    

  • 为什么需要知道它是否可以为null?您是指“引用类型”还是“可为空的”

    无论哪种方式,对于字符串值,最简单的选项都是通过
    类型转换器
    ,这在
    PropertyDescriptor
    上更容易(更准确)获得:

    PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);
    // then per property...
    PropertyDescriptor prop = props[propName];
    prop.SetValue(obj, prop.Converter.ConvertFromInvariantString(value));
    

    即使按属性(而不是按类型)设置,也应使用正确的转换器。最后,如果你做了很多这方面的工作,这允许通过加速,而不改变代码(除了为类型启用它,只执行一次)。

    我创建了一个小示例。如果您对此代码有任何疑问,请添加注释

    编辑:根据Marc Gravell的精彩评论更新样本

    class Program
    {
        public int? NullableProperty { get; set; }
    
        static void Main(string[] args)
        {
            var value = "123";
            var program = new Program();
            var property = typeof(Program).GetProperty("NullableProperty");
    
            var propertyDescriptors = TypeDescriptor.GetProperties(typeof(Program));
            var propertyDescriptor = propertyDescriptors.Find("NullableProperty", false);
            var underlyingType =  
                Nullable.GetUnderlyingType(propertyDescriptor.PropertyType);
    
            if (underlyingType != null)
            {
                var converter = propertyDescriptor.Converter;
                if (converter != null && converter.CanConvertFrom(typeof(string)))
                {
                    var convertedValue = converter.ConvertFrom(value);
                    property.SetValue(program, convertedValue, null);
                    Console.WriteLine(program.NullableProperty);
                }
            }
    
        }
    }
    

    具体而言,要将整数转换为枚举并分配给可为空的枚举属性,请执行以下操作:

    int value = 4;
    if(propertyInfo.PropertyType.IsGenericType
    && Nullable.GetUnderlyingType(propertyInfo.PropertyType) != null
    && Nullable.GetUnderlyingType(propertyInfo.PropertyType).IsEnum)
    {
        var enumType = Nullable.GetUnderlyingType(propertyInfo.PropertyType);
        var enumValue = Enum.ToObject(enumType, value);
        propertyInfo.SetValue(item, enumValue, null);
    
        //-- suggest by valamas
        //propertyInfo.SetValue(item, (value == null ? null : enumValue), null);
    }
    

    最初,在中提到了最佳解决方案。然而,当您需要实现动态解决方案时,您不知道一个类上可以声明多少个可为null的字段,最好的办法是检查是否可以将可为null的类型分配给 属性,通过反射检查该属性

    protected T initializeMe<T>(T entity, Value value)
    {
      Type eType = entity.GetType();
      foreach (PropertyInfo pi in eType.GetProperties())
            {
                //get  and nsame of the column in DataRow              
                Type valueType = pi.GetType();                
                if (value != System.DBNull.Value )
                {
                 pi.SetValue(entity, value, null);
                }
                else if (valueType.IsGenericType && typeof(Nullable<>).IsAssignableFrom(valueType)) //checking if nullable can be assigned to proptety
                {
                 pi.SetValue(entity, null, null);
                }
                else
                {
                 System.Diagnostics.Trace.WriteLine("something here");
                }
                ...
            }
    ...
    }
    
    受保护的T初始化项(T实体,值)
    {
    类型eType=entity.GetType();
    foreach(eType.GetProperties()中的PropertyInfo pi)
    {
    //获取并命名DataRow中列的名称
    Type valueType=pi.GetType();
    if(值!=System.DBNull.value)
    {
    pi.SetValue(实体、值、空);
    }
    else if(valueType.IsGenericType&&typeof(Nullable).IsAssignableFrom(valueType))//检查是否可以将Nullable分配给proptety
    {
    pi.SetValue(实体,null,null);
    }
    其他的
    {
    System.Diagnostics.Trace.WriteLine(“此处某物”);
    }
    ...
    }
    ...
    }
    
    以下是“可为空”对象类型的最安全解决方案

    if (reader[rName] != DBNull.Value)
    
        {
            PropertyInfo pi = (PropertyInfo)d[rName.ToLower()];
            if (pi.PropertyType.FullName.ToLower().Contains("nullable"))
                pi.SetValue(item, reader[rName]);
            else
                pi.SetValue(item, Convert.ChangeType(reader[rName], Type.GetType(pi.PropertyType.FullName)), null);
    
        }
    

    我使用了下面的解决方案,避免使用类型转换器来控制代码

    我编写了一个支持操作的助手类

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Reflection;
    using System.Text;
    
    public static class ObjectExtensions
    {
        /// <summary>
        /// Enable using reflection for setting property value 
        /// on every object giving property name and value.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="target"></param>
        /// <param name="propertyName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool SetProperty<T>(this T target, string propertyName, object value)
        {
            PropertyInfo pi = target.GetType().GetProperty(propertyName);
            if (pi == null)
            {
                Debug.Assert(false);
                return false;
            }
    
            try
            {
                // Convert the value to set to the properly type
                value = ConvertValue(pi.PropertyType, value);
    
                // Set the value with the correct type
                pi.SetValue(target, value, null);
            }
            catch (Exception ex)
            {
                Debug.Assert(false);
                return false;
            }
            return true;
        }
    
    
        private static object ConvertValue(Type propertyType, object value)
        {
            // Check each type You need to handle
            // In this way You have control on conversion operation, before assigning value
            if (propertyType == typeof(int) ||
                propertyType == typeof(int?))
            {
                int intValue;
                if (int.TryParse(value.ToString(), out intValue))
                    value = intValue;
            }
            else if (propertyType == typeof(byte) ||
                    propertyType == typeof(byte?))
            {
                byte byteValue;
                if (byte.TryParse(value.ToString(), out byteValue))
                    value = byteValue;
            }
            else if (propertyType == typeof(string))
            {
                value = value.ToString();
            }
            else
            {
                // Extend Your own handled types
                Debug.Assert(false);
            }
    
            return value;
        }
    }
    
    使用系统;
    使用System.Collections.Generic;
    使用系统诊断;
    运用系统反思;
    使用系统文本;
    公共静态类对象扩展
    {
    /// 
    ///启用使用反射设置属性值
    ///在每个对象上指定属性名称和值。
    /// 
    /// 
    /// 
    /// 
    /// 
    /// 
    公共静态bool SetProperty(此T目标、字符串propertyName、对象值)
    {
    PropertyInfo pi=target.GetType().GetProperty(propertyName);
    if(pi==null)
    {
    Assert(false);
    返回false;
    }
    尝试
    {
    //将要设置的值转换为正确的类型
    value=ConvertValue(pi.PropertyType,value);
    //使用正确的类型设置值
    pi.SetValue(目标、值、空);
    }
    捕获(例外情况除外)
    {
    Assert(false);
    返回false;
    }
    返回true;
    }
    私有静态对象值(类型propertyType,对象值)
    {
    //检查需要处理的每种类型
    //通过这种方式,您可以在赋值之前控制转换操作
    if(propertyType==typeof(int)||
    propertyType==typeof(int?)
    {
    int值;
    if(int.TryParse(value.ToString(),out intValue))
    value=intValue;
    }
    else if(propertyType==typeof(字节)||
    propertyType==typeof(字节?)
    {
    字节字节值;
    if(byte.TryParse(value.ToString(),out byteValue))
    值=字节值;
    }
    else if(propertyType==typeof(string))
    {
    value=value.ToString();
    }
    其他的
    {
    //扩展您自己的句柄类型
    Assert(false);
    }
    返回值;
    }
    }
    
    注意:设置可空值(例如int?)时,该值几乎必须是整数或可转换类型。不能在字节?上设置int。因此,需要正确转换。请参阅ConvertValue()代码,该代码检查类型(int)和相应的可空类型(int?)

    这是用于设置具有所需数据结构(字典)的值的代码

        public class Entity
        {
            public string Name { get; set; }
            public byte? Value { get; set; }
        }
    
        static void SetNullableWithReflection()
        {
            // Build array as requested
            Dictionary<string, string> props = new Dictionary<string, string>();
            props.Add("Name", "First name");
            props.Add("Value", "1");
    
            // The entity
            Entity entity = new Entity();
    
            // For each property to assign with a value
            foreach (var item in props)
                entity.SetProperty(item.Key, item.Value);
    
            // Check result
            Debug.Assert(entity.Name == "First name");
            Debug.Assert(entity.Value == 1);
        }
    
    公共类实体
    {
    公共字符串名称{get;set;}
    公共字节?值{get;set;}
    }
    静态void SetNullableWithReflection()
    {
    //按要求生成阵列
    字典道具=新字典();
    添加(“姓名”、“名字”);
    道具。增加(“价值”、“1”);
    //实体
    实体=新实体();
    //为每个属性指定一个值
    foreach(道具中的var项目)
    entity.SetProperty(item.Key,item.Value);
    //检查结果
    
        public class Entity
        {
            public string Name { get; set; }
            public byte? Value { get; set; }
        }
    
        static void SetNullableWithReflection()
        {
            // Build array as requested
            Dictionary<string, string> props = new Dictionary<string, string>();
            props.Add("Name", "First name");
            props.Add("Value", "1");
    
            // The entity
            Entity entity = new Entity();
    
            // For each property to assign with a value
            foreach (var item in props)
                entity.SetProperty(item.Key, item.Value);
    
            // Check result
            Debug.Assert(entity.Name == "First name");
            Debug.Assert(entity.Value == 1);
        }