我有一个第三方库,它使用反射设置给定的对象属性,如下所示。(这是简化版)
public void Set(object obj, string prop, object value) {
var propInf = obj.GetType().GetProperty(prop);
value = Convert.ChangeType(value, propInf.PropertyType);
propInf.SetValue(obj, value, null);
}
我们有一个可空属性的类
class Test
{
public int? X { get; set; }
}
当我写下面的代码时,它说它不能将int
转换为int?
var t = new Test();
Set(t, "X", 1);
由于Nullable不实现IConvertible,所以它是有意义的。然后我决定编写一个方法,返回给定值类型对象的可空版本。
public object MakeNullable(object obj) {
if(obj == null || !obj.GetType().IsValueType)
throw new Exception("obj must be value type!");
return Activator.CreateInstance(
typeof(Nullable<>).MakeGenericType(obj.GetType()),
new[] { obj });
}
我希望这样使用这个方法。
var t = new Test();
Set(t, "X", MakeNullable(1));
但它仍然说不能将int
转化为int?
。当我调试typeof(Nullable<>).MakeGenericType(obj.GetType())
等于int?
,但Activator.CreateInstace
返回int
值不是int?
所以这是我的情况…任何帮助吗?
应该可以:
public static object ChangeType(object value, Type conversionType)
{
if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
if (value == null)
return null;
var nullableConverter = new NullableConverter(conversionType);
conversionType = nullableConverter.UnderlyingType;
}
return Convert.ChangeType(value, conversionType);
}
试试下面的代码…
public void Set(object obj, string prop, object value)
{
//var propInf = obj.GetType().GetProperty(prop);
//value = Convert.ChangeType(value, propInf.PropertyType);
//propInf.SetValue(obj, value, null);
var property = obj.GetType().GetProperty(prop);
if (property != null)
{
Type t = Nullable.GetUnderlyingType(property.PropertyType)
?? property.PropertyType;
object safeValue = (value == null) ? null
: Convert.ChangeType(value, t);
property.SetValue(obj, safeValue, null);
}
}
Convert.ChangeType()在可空类型上失败通过LukeH
更新:隐藏基方法。
namespace ConsoleApplication2
{
using System;
using System.Collections.Generic;
using System.Linq;
internal class Program
{
private static void Main(string[] args)
{
EnterPoint t = new EnterPoint();
t.BeginProcess();
}
}
public class EnterPoint
{
public void BeginProcess()
{
var t = new Test(); //Object
try
{
baseDllMethod m = new baseDllMethod(); //Your DLL
m.Set(t, "X", 1); //Problem Method, this give you error
}
catch (Exception ex)
{
Console.WriteLine("ERROR EN DLL METHOD");
}
xyz_D der = new xyz_D(); //Derivated method
der.Set(t, "X", 1) ; //HIDE BASE METHOD
}
}
public class baseDllMethod //YOUR DLL HERE
{
public void Set(object obj, string prop, object value)
{
var propInf = obj.GetType().GetProperty(prop);
value = Convert.ChangeType(value, propInf.PropertyType);
propInf.SetValue(obj, value, null);
}
}
public class xyz_D : baseDllMethod //Inherits
{
public new void Set(object obj, string prop, object value) //Hide base method
{
var property = obj.GetType().GetProperty(prop);
if (property != null)
{
Type t = Nullable.GetUnderlyingType(property.PropertyType)
?? property.PropertyType;
object safeValue = (value == null) ? null
: Convert.ChangeType(value, t);
property.SetValue(obj, safeValue, null);
}
}
}
public class Test //Your Object
{
public int? X { get; set; }
}
}