4

本质上,我正在尝试使用

field.SetValue(obj, val);

Whereval的类型可以隐式转换为真正的字段类型,但不能“直接”分配。当然,我得到了通常的ArgumentException: Object type cannot be converted to target type. 有没有办法在不手动查找和调用构造函数的情况下做到这一点?

4

2 回答 2

2

尝试使用 Convert.ChangeType:

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

检查以下使用字符串值通过反射设置属性以获取更多信息。

于 2013-08-22T00:24:52.297 回答
2

这是一个相当复杂的问题,我不知道如何让它在一行中工作。虽然Convert.ChangeType适用于简单情况,但在以下情况下会失败:

  • 目标类型是 Nullable 枚举,并且您使用整数值(不是枚举值):在这种情况下,您需要使用Enum.ToObject它来使其工作。

  • 您的值是 DBNull.Value :在这种情况下,您需要对其进行测试并分配 null

  • 目标类型与您要设置的值不是同一类型的数字:Convert.ChangeType将在此处为您提供帮助。

这是一个说明如何执行此操作的示例:

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

功能的单元测试:

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

    }
}
于 2013-08-22T02:07:29.050 回答