使用 FastMember 为 Nullable<T> 赋值
Assign value to Nullable<T> using FastMember
我已使用此函数成功地为属性和嵌套属性赋值
private static void AssignValueToProperty(ObjectAccessor accessor, object value, string propertyLambdaString)
{
var index = propertyLambdaString.IndexOf('.');
if (index == -1)
{
accessor[propertyLambdaString] = value;
// problem above: throws Exception if assigning value to Nullable<T>
}
else
{
var property = propertyLambdaString.Substring(0, index);
accessor = ObjectAccessor.Create(accessor[property]);
AssignValueToProperty(accessor, value, propertyLambdaString.Substring(index + 1));
}
}
但是,赋值抛出 InvalidCastException。如何分配可空值而不是使用 FastMember?例如
public class A
{
public double? SomeValue {get; set;}
}
...
var a = new A();
var accessor = ObjectAccessor.Create(a);
accessor["SomeValue"] = 100; // throws Exception, when assigning 100.0 it works???
FastMember 不会为您转换类型。 100 是一个 int 文字,但目标 属性 是 decimal? 类型。没有从 int 到 decimal 的隐式转换? (或十进制)。 100.0 是一个 Double 字面值,它隐式转换为十进制?,因此赋值将成功。
public class A
{
public double? SomeValue { get; set; }
}
public static class Sample
{
public static void Go()
{
var a = new A();
var accessor = ObjectAccessor.Create(a);
accessor["SomeValue"] = 100.0; // succeeds
accessor["SomeValue"] = 100M; // succeeds
accessor["SomeValue"] = null; // succeeds
accessor["SomeValue"] = 100; // throws, can't convert from int to decimal?
}
}
如果没有隐式转换,您将必须在代码中执行必要的转换。
隐式转换:
https://msdn.microsoft.com/en-us/library/y5b434w4.aspx
显式转换:
FastMember 在它的工具箱中与类型转换没有任何关系,所以这是我想出的解决方案作为 FastMember 的扩展方法 ObjectAccessor
:
public static class FastMemberExtensions
{
public static void AssignValueToProperty(this ObjectAccessor accessor, string propertyName, object value)
{
var index = propertyName.IndexOf('.');
if (index == -1)
{
var targetType = Expression.Parameter(accessor.Target.GetType());
var property = Expression.Property(targetType, propertyName);
var type = property.Type;
type = Nullable.GetUnderlyingType(type) ?? type;
value = value == null ? GetDefault(type) : Convert.ChangeType(value, type);
accessor[propertyName] = value;
}
else
{
accessor = ObjectAccessor.Create(accessor[propertyName.Substring(0, index)]);
AssignValueToProperty(accessor, propertyName.Substring(index + 1), value);
}
}
private static object GetDefault(Type type)
{
return type.IsValueType ? Activator.CreateInstance(type) : null;
}
}
可以这样调用:
var accessor = ObjectAccessor.Create(t); // t is instance of SomeType
accessor.AssignValueToProperty("Nested.Property", value); // t.Nested.Property = value
我已使用此函数成功地为属性和嵌套属性赋值
private static void AssignValueToProperty(ObjectAccessor accessor, object value, string propertyLambdaString)
{
var index = propertyLambdaString.IndexOf('.');
if (index == -1)
{
accessor[propertyLambdaString] = value;
// problem above: throws Exception if assigning value to Nullable<T>
}
else
{
var property = propertyLambdaString.Substring(0, index);
accessor = ObjectAccessor.Create(accessor[property]);
AssignValueToProperty(accessor, value, propertyLambdaString.Substring(index + 1));
}
}
但是,赋值抛出 InvalidCastException。如何分配可空值而不是使用 FastMember?例如
public class A
{
public double? SomeValue {get; set;}
}
...
var a = new A();
var accessor = ObjectAccessor.Create(a);
accessor["SomeValue"] = 100; // throws Exception, when assigning 100.0 it works???
FastMember 不会为您转换类型。 100 是一个 int 文字,但目标 属性 是 decimal? 类型。没有从 int 到 decimal 的隐式转换? (或十进制)。 100.0 是一个 Double 字面值,它隐式转换为十进制?,因此赋值将成功。
public class A
{
public double? SomeValue { get; set; }
}
public static class Sample
{
public static void Go()
{
var a = new A();
var accessor = ObjectAccessor.Create(a);
accessor["SomeValue"] = 100.0; // succeeds
accessor["SomeValue"] = 100M; // succeeds
accessor["SomeValue"] = null; // succeeds
accessor["SomeValue"] = 100; // throws, can't convert from int to decimal?
}
}
如果没有隐式转换,您将必须在代码中执行必要的转换。
隐式转换:
https://msdn.microsoft.com/en-us/library/y5b434w4.aspx
显式转换:
FastMember 在它的工具箱中与类型转换没有任何关系,所以这是我想出的解决方案作为 FastMember 的扩展方法 ObjectAccessor
:
public static class FastMemberExtensions
{
public static void AssignValueToProperty(this ObjectAccessor accessor, string propertyName, object value)
{
var index = propertyName.IndexOf('.');
if (index == -1)
{
var targetType = Expression.Parameter(accessor.Target.GetType());
var property = Expression.Property(targetType, propertyName);
var type = property.Type;
type = Nullable.GetUnderlyingType(type) ?? type;
value = value == null ? GetDefault(type) : Convert.ChangeType(value, type);
accessor[propertyName] = value;
}
else
{
accessor = ObjectAccessor.Create(accessor[propertyName.Substring(0, index)]);
AssignValueToProperty(accessor, propertyName.Substring(index + 1), value);
}
}
private static object GetDefault(Type type)
{
return type.IsValueType ? Activator.CreateInstance(type) : null;
}
}
可以这样调用:
var accessor = ObjectAccessor.Create(t); // t is instance of SomeType
accessor.AssignValueToProperty("Nested.Property", value); // t.Nested.Property = value