Search code examples
c#propertiesnullablefastmember

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

Solution

  • 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