C# 通过反射设置属性时的类型转换问题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13270183/
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
Type conversion issue when setting property through reflection
提问by Shikyo
We have a property of type long?that gets filled with an int.
我们有一个类型long?为int.
This works fine when i just set the property directly obj.Value = v;but when i try and set the property through reflection info.SetValue(obj, v, null);it gives me a the following exception:
当我直接设置属性时,这很好用,obj.Value = v;但是当我尝试通过反射设置属性时,info.SetValue(obj, v, null);它给了我以下异常:
Object of type 'System.Int32' cannot be converted to type 'System.Nullable`1[System.Int64]'.
“System.Int32”类型的对象无法转换为“System.Nullable`1[System.Int64]”类型。
This is a simplified scenario:
这是一个简化的场景:
class TestClass
{
public long? Value { get; set; }
}
[TestMethod]
public void TestMethod2()
{
TestClass obj = new TestClass();
Type t = obj.GetType();
PropertyInfo info = t.GetProperty("Value");
int v = 1;
// This works
obj.Value = v;
// This does not work
info.SetValue(obj, v, null);
}
Why does it not work when setting the property through reflectionwhile it works when setting the property directly?
为什么reflection直接设置属性时,设置属性时不起作用,而直接设置属性时有效?
采纳答案by Pranay Rana
Check full article : How to set value of a property using Reflection?
查看完整文章: 如何使用反射设置属性的值?
full code if you are setting value for nullable type
完整代码,如果您要为可空类型设置值
public static void SetValue(object inputObject, string propertyName, object propertyVal)
{
//find out the type
Type type = inputObject.GetType();
//get the property information based on the type
System.Reflection.PropertyInfo propertyInfo = type.GetProperty(propertyName);
//find the property type
Type propertyType = propertyInfo.PropertyType;
//Convert.ChangeType does not handle conversion to nullable types
//if the property type is nullable, we need to get the underlying type of the property
var targetType = IsNullableType(propertyType) ? Nullable.GetUnderlyingType(propertyType) : propertyType;
//Returns an System.Object with the specified System.Type and whose value is
//equivalent to the specified object.
propertyVal = Convert.ChangeType(propertyVal, targetType);
//Set the value of the property
propertyInfo.SetValue(inputObject, propertyVal, null);
}
private static bool IsNullableType(Type type)
{
return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>));
}
you need to convert value like this i.e you need to convert value to your property type like as below
您需要像这样转换值,即您需要将值转换为您的属性类型,如下所示
PropertyInfo info = t.GetProperty("Value");
object value = null;
try
{
value = System.Convert.ChangeType(123,
Nullable.GetUnderlyingType(info.PropertyType));
}
catch (InvalidCastException)
{
return;
}
propertyInfo.SetValue(obj, value, null);
you need to do this because you cannot convert any arbirtary value to given type...so you need to convert it like this
你需要这样做,因为你不能将任何任意值转换为给定的类型......所以你需要像这样转换它
回答by fsimonazzi
When you write:
当你写:
obj.Value = v;
the compiler knows how to do the proper casting for you and actually compiles
编译器知道如何为您进行正确的转换并实际编译
obj.Value = new long?((long) v);
When your use reflection there is no compiler to help you.
当您使用反射时,没有编译器可以帮助您。
回答by LightStriker
Because the type longhas an implicit conversion method.
因为类型long有隐式转换方法。
6.1.2 Implicit numeric conversions
You can see implicit conversion method as hidden method that exist behind the =symbol.
您可以将隐式转换方法视为存在于=符号后面的隐藏方法。
It also work with nullable type:
它也适用于可为空类型:
int i = 0;
int? j = i; // Implicit conversion
long k = i; // Implicit conversion
long? l = i; // Implicit conversion
But going the other way around doesn't work, because no implicit conversion exist to pass a nullto a non-null:
但是反过来是行不通的,因为不存在将 a 传递null给非 null 的隐式转换:
int? i = 0;
int j = i; // Compile assert. An explicit conversion exit...
int k = (int)i; // Compile, but if i is null, you will assert at runtime.
You don't have to explicitly convert a intto a int?... or a long?.
您不必显式地将 a 转换int为 a int?... 或 a long?。
However, when you use reflection, you are bypassing implicit conversion and assign directly the value to the property. This way, you have to convert it explicitly.
但是,当您使用反射时,您将绕过隐式转换并直接将值分配给属性。这样,您必须显式转换它。
info.SetValue(obj, (long?)v, null);
Reflection skip all the sweet stuff hidden behind =.
反思跳过隐藏在背后的所有甜蜜的东西=。
回答by DiskJunky
Consolidating and expanding on Pranay Rana's answer to handle enums as suggested by SilverNinja(and answered by thecoop) and put accumulated the learnings in one place. This is a little more copy/pastable.;
巩固和扩大Pranay蛙的回答来处理enum所建议小号SilverNinja(并回答thecoop),并把在一个地方积累的学习收获。这是一个多一点的复制/粘贴。
private void SetApiSettingValue(object source, string propertyName, object valueToSet)
{
// find out the type
Type type = source.GetType();
// get the property information based on the type
System.Reflection.PropertyInfo property = type.GetProperty(propertyName);
// Convert.ChangeType does not handle conversion to nullable types
// if the property type is nullable, we need to get the underlying type of the property
Type propertyType = property.PropertyType;
var targetType = IsNullableType(propertyType) ? Nullable.GetUnderlyingType(propertyType) : propertyType;
// special case for enums
if (targetType.IsEnum)
{
// we could be going from an int -> enum so specifically let
// the Enum object take care of this conversion
if (valueToSet != null)
{
valueToSet = Enum.ToObject(targetType, valueToSet);
}
}
else
{
// returns an System.Object with the specified System.Type and whose value is
// equivalent to the specified object.
valueToSet = Convert.ChangeType(valueToSet, targetType);
}
// set the value of the property
property.SetValue(source, valueToSet, null);
}
private bool IsNullableType(Type type)
{
return type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>));
}
回答by DShook
I also ran into this problem when creating new objects reflectively.
我在反射性地创建新对象时也遇到了这个问题。
This is how not to do it:
这是不这样做的方法:
var newOne = Activator.CreateInstance(srcProp.GetType());
srcProp.SetValue(newGameData, newOne, null);
And this is how to do it:
这是如何做到的:
var newOne = Activator.CreateInstance(srcProp.PropertyType);
srcProp.SetValue(newGameData, newOne, null);
回答by Fer R
This is old thread. But solutions in this page didn't work. I did some adjust and works great (in .netcore 2.0)!
这是旧线程。但是此页面中的解决方案不起作用。我做了一些调整并且效果很好(在 .netcore 2.0 中)!
obj = Activator.CreateInstance<T>();
foreach (PropertyInfo prop in obj.GetType().GetProperties())
{
if (!object.Equals(this.reader[prop.Name], DBNull.Value))
{
if (prop.PropertyType.Name.Contains("Nullable"))
{
prop.SetValue(obj, Convert.ChangeType(this.reader[prop.Name], Nullable.GetUnderlyingType(prop.PropertyType)), null);
}
else
{
prop.SetValue(obj, this.reader[prop.Name], null);
}
}
}

