vendredi 4 mai 2018

Copying a Nullable property's value via reflection from object to object fails because value is non-nullable

TL;DR;

Is there a way to set a nullable property to a value with the same type of the nullable's underlying one?

I am trying to do a partial shallow copy of an object via C# reflection. Specifically, I want to copy all properties appearing in an instance of object A (this) into an instance of object T (destination).

This is the code I wrote:

public void CopyTo<T>(T destination)
{
    var sources = typeof(A).GetProperties(
        System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);

    var targets = typeof(T).GetProperties(
        System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);

    foreach (var sourceField in sources)
    {
        var sourceValue = sourceField.GetValue(this);
        var target = targets.Single(x => x.Name == sourceField.Name);
        target.SetValue(sourceValue, destination);
    }
}

This fails when the property is a Nullable<>, because GetValue returns the value of the underlying type of the nullable.


My first hunch was to cast sourceValue to the correct type, but I had the following problems with it:

Casting with System.Convert.ChangeType(sourceField.GetValue(this), sourceField.PropertyType) fails with this:

System.InvalidCastException : Invalid cast from 'System.Single' to 'System.Nullable`1[[System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.
   at System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider)
   at System.Single.System.IConvertible.ToType(Type type, IFormatProvider provider)
   at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
   at System.Convert.ChangeType(Object value, Type conversionType)

Casting with (sourceField.PropertyType)sourceField.GetValue(this) does not compile:

'sourceField' is a variable but is used like a type


My second hunch was to use the SetValue overload in case of a nullable (specifying null as index as suggested by the Internet), but that also doesn't work.





Aucun commentaire:

Enregistrer un commentaire