2013-08-22 4 views
2

Essentiellement, je suis en train d'utiliseraide SetValue avec conversion implicite

field.SetValue(obj, val); 

val « s de type peut être converti implicitement le vrai type de champ, mais pas « directement » assignable. Bien sûr, je reçois l'habituel ArgumentException: Object type cannot be converted to target type. Existe-t-il un moyen de le faire sans rechercher et appeler manuellement le constructeur?

Répondre

2

Essayez avec Convert.ChangeType:

field.SetValue(obj, Convert.ChangeType(val, field.PropertyType), null); 

Vérifiez les points suivants Setting a property by reflection with a string value plus d'information.

+0

J'ai essayé, mais je l'avais alors besoin de mettre en œuvre IConvertible interfaces, que je pouvais faire, mais j'essaie de trouver une autre façon –

2

Ceci est une question assez compliquée, et je ne connais pas un moyen de le faire fonctionner dans une ligne de sigle. Alors que les Convert.ChangeType œuvres pour les cas simples, il échouera dans les cas suivants:

  • Le type de cible est un ENUM Nullable, et que vous utilisez une valeur entière (et non une valeur ENUM): dans ce cas, vous J'ai besoin d'utiliser Enum.ToObject pour le faire fonctionner.

  • Votre valeur est DBNull.Value: Vous aurez besoin de le tester et affecter null dans ce cas

  • Le type de cible n'est pas le même type de numéro que la valeur que vous souhaitez définir: Convert.ChangeType aidera vous ici.

Voici un exemple qui illustre comment le faire:

public void SetFieldValue(FieldInfo field, object targetObj, object value) 
{ 
    object valueToSet; 

    if (value == null || value == DBNull.Value) 
    { 
     valueToSet = null; 
    } 
    else 
    { 
     Type fieldType = field.FieldType; 
     //assign enum 
     if (fieldType.IsEnum) 
      valueToSet = Enum.ToObject(fieldType, value); 
     //support for nullable enum types 
     else if (fieldType.IsValueType && IsNullableType(fieldType)) 
     { 
      Type underlyingType = Nullable.GetUnderlyingType(fieldType); 
      valueToSet = underlyingType.IsEnum ? Enum.ToObject(underlyingType, value) : value; 
     } 
     else 
     { 
      //we always need ChangeType, it will convert the value to the proper number type, for example. 
      valueToSet = Convert.ChangeType(value, fieldType); 
     } 
    } 
    field.SetValue(targetObj, valueToSet); 
} 

Un test unitaire pour la fonction:

enum TestEnum 
{ 
    DummyValue 
} 

class TestClass 
{ 
    public int IntValue; 
    public decimal DecimalValue; 
    public int? NullableInt; 
    public TestEnum EnumValue; 
    public TestEnum? NullableEnumValue; 
    public TestClass ObjectValue; 
} 

[TestFixture] 
public class DataObjectBinderFixture 
{ 
    private TestClass _testObject; 

    private void SetFieldValue(string fieldName, object value) 
    { 
     var fieldInfo = typeof (TestClass).GetField(fieldName); 
     ReflectionUtils.SetFieldValue(fieldInfo, _testObject, value); 
    } 

    [Test] 
    public void TestSetValue() 
    { 
     _testObject = new TestClass(); 

     SetFieldValue("IntValue", 2.19); 
     SetFieldValue("IntValue", DBNull.Value); 
     SetFieldValue("DecimalValue", 1); 

     SetFieldValue("NullableInt", null); 
     SetFieldValue("NullableInt", 12); 

     SetFieldValue("EnumValue", TestEnum.DummyValue); 
     SetFieldValue("EnumValue", 0); 

     SetFieldValue("NullableEnumValue", TestEnum.DummyValue); 
     SetFieldValue("NullableEnumValue", null); 
     SetFieldValue("NullableEnumValue", 0); 
     SetFieldValue("NullableEnumValue", DBNull.Value); 

     SetFieldValue("ObjectValue", DBNull.Value); 

    } 
}