如何通过反射代码(c#)设置可为空类型?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/446522/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
how to set nullable type via reflection code ( c#)?
提问by dotnetcoder
I need to set the properties of a class using reflection.
我需要使用反射设置类的属性。
I have a Dictionary<string,string>
with property names and string values.
我有一个Dictionary<string,string>
属性名称和字符串值。
Inside a reflection loop, I need to convert the string value to the appropriate property type while setting the value for each property. Some of these property types are nullable types.
在反射循环中,我需要将字符串值转换为适当的属性类型,同时为每个属性设置值。其中一些属性类型是可为空类型。
- How can I know from PropertyInfo if the property is a nullable type?
- How can I set a nullable type using reflection?
- 我如何从 PropertyInfo 知道该属性是否为可空类型?
- 如何使用反射设置可为空类型?
edit:The first method defined in the comments on this blog seems to do the trick as well: http://weblogs.asp.net/pjohnson/archive/2006/02/07/437631.aspx
编辑:本博客评论中定义的第一种方法似乎也能解决问题:http: //weblogs.asp.net/pjohnson/archive/2006/02/07/437631.aspx
采纳答案by Kent Boogaart
One way to do this is:
type.GetGenericTypeDefinition() == typeof(Nullable<>)
Just set is as per any other reflection code:
propertyInfo.SetValue(yourObject, yourValue);
一种方法是:
type.GetGenericTypeDefinition() == typeof(Nullable<>)
只需按照任何其他反射代码进行设置:
propertyInfo.SetValue(yourObject, yourValue);
回答by dotnetcoder
Checking for Nullable types is easy, int? is actually System.Nullable<System.Int32>
.
So you just check if the type is a generic instance of System.Nullable<T>
.
Setting shouldn't make a difference, nullableProperty.SetValue(instance, null)
or nullableProperty.SetValue(instance, 3)
检查 Nullable 类型很容易,int?实际上是System.Nullable<System.Int32>
。因此,您只需检查该类型是否是System.Nullable<T>
. 设置不应该有所作为,nullableProperty.SetValue(instance, null)
或者nullableProperty.SetValue(instance, 3)
回答by Marc Gravell
Why do you need to know if it is nullable? And do you mean "reference-type", or "Nullable<T>
"?
为什么你需要知道它是否可以为空?你的意思是“引用类型”还是“ Nullable<T>
”?
Either way, with string values, the easiest option would be via the TypeConverter
, which is more-easily (and more accurately) available on PropertyDescriptor
:
无论哪种方式,对于字符串值,最简单的选择是通过TypeConverter
,这在 上更容易(也更准确)可用PropertyDescriptor
:
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(obj);
// then per property...
PropertyDescriptor prop = props[propName];
prop.SetValue(obj, prop.Converter.ConvertFromInvariantString(value));
This should use the correct converter, even if set per-property (rather than per-type). Finally, if you are doing lots of this, this allows for acceleration via HyperDescriptor
, without changing the code (other than to enable it for the type, done once only).
这应该使用正确的转换器,即使设置每个属性(而不是每个类型)。最后,如果你做了很多这样的事情,这允许通过 加速HyperDescriptor
,而无需更改代码(除了为类型启用它,只完成一次)。
回答by aku
I've created small sample. If you have any questions regarding this code, please add comments.
我创建了小样本。如果您对此代码有任何疑问,请添加评论。
EDIT: updated sample based on great comment by Marc Gravell
编辑:根据 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);
}
}
}
}
回答by Joel
Specifically to convert an integer to an enum and assign to a nullable enum property:
特别是将整数转换为枚举并分配给可为空的枚举属性:
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);
}
回答by Seego
Originally, the best solution is mentioned at MSDN forum. However, when you need to implement dynamic solution, where you don't know exactly how many nullable fields may be declared on a class, you best bet is to check if Nullable<> type can be assigned to the property, which you inspect via reflection
最初,最佳解决方案是在MSDN 论坛上提到的。但是,当您需要实现动态解决方案时,您不知道在一个类上可以确切地声明有多少可空字段,您最好检查是否可以将 Nullable<> 类型分配给属性,您可以通过检查反射
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");
}
...
}
...
}
回答by Smager
here is the safest solution for "nullable" object type
这是“可为空”对象类型的最安全解决方案
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);
}
回答by RFex
I have used the following solution, avoiding use of type converter for taking more control over code.
我使用了以下解决方案,避免使用类型转换器来更好地控制代码。
I wrote a helper class for supporting operations
我写了一个辅助类来支持操作
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;
}
}
Note: When You set a nullable value (eg. int?, the value need to be almost an integer or castable type. You cannot set int on a byte?. So, You need to convert properly. See ConvertValue() code, that checks either for type (int) and corresponding nullable type (int?) )
注意:当你设置一个可为空的值时(例如。int?,该值需要几乎是整数或可转换类型。你不能在字节上设置int?。所以,你需要正确转换。参见ConvertValue()代码,即检查类型 (int) 和相应的可为空类型 (int?) )
This is code for setting values with the required data structure, Dictionary.
这是使用所需的数据结构字典设置值的代码。
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);
}