简体   繁体   中英

Assign value to Nullable<T> using FastMember

I have successfully assigned values to Properties and nested Properties using this function

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));
    }
}

However, the assignment throws an InvalidCastException. How to assign nullable values instead using FastMember? For example

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 has nothing related to type conversion within it's toolbox, so this is the solution I came up with as Extension Method for 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;
    }
}

Can be called this way:

var accessor = ObjectAccessor.Create(t); // t is instance of SomeType
accessor.AssignValueToProperty("Nested.Property", value); // t.Nested.Property = value

FastMember is not going to convert types for you. 100 is an int literal, but the target property is of type decimal?. There is no implicit conversion from int to decimal? (or decimal). 100.0 is a Double literal which implicitly converts to decimal?, and thus the assignment will succeed.

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?
    }
}

If there is not an implicit conversion, you'll have to perform necessary conversions in your code.

Implicit conversions:

https://msdn.microsoft.com/en-us/library/y5b434w4.aspx

Explicit conversions:

https://msdn.microsoft.com/en-us/library/yht2cx7b.aspx

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM