我想将一个字符串转换为对象属性值,其名称为字符串。我试着这样做:

string modelProperty = "Some Property Name";
string value = "SomeValue";
var property = entity.GetType().GetProperty(modelProperty);
if (property != null) {
    property.SetValue(entity, 
        Convert.ChangeType(value, property.PropertyType), null);
}

问题是,当属性类型是可空类型时,这将失败并抛出无效强制转换异常。这不是无法转换值的情况-如果我手动这样做,它们将工作(例如DateTime?d = Convert.ToDateTime(value);)我见过一些类似的问题,但仍然不能让它工作。


当前回答

我也有类似的需求,而LukeH的回答为我指明了方向。我用这个通用函数来简化。

    public static Tout CopyValue<Tin, Tout>(Tin from, Tout toPrototype)
    {
        Type underlyingT = Nullable.GetUnderlyingType(typeof(Tout));
        if (underlyingT == null)
        { return (Tout)Convert.ChangeType(from, typeof(Tout)); }
        else
        { return (Tout)Convert.ChangeType(from, underlyingT); }
    }

用法是这样的:

        NotNullableDateProperty = CopyValue(NullableDateProperty, NotNullableDateProperty);

注意,第二个参数只是作为一个原型来显示函数如何强制转换返回值,因此它实际上不必是目标属性。这意味着你也可以这样做:

        DateTime? source = new DateTime(2015, 1, 1);
        var dest = CopyValue(source, (string)null);

我用这种方法代替了out因为你不能在属性中使用out。实际上,它可以使用属性和变量。如果需要,也可以创建重载来传递该类型。

其他回答

为了做到这一点,你必须获得底层类型……

试试这个,我已经成功地使用了泛型:

//Coalesce to get actual property type...
Type t = property.PropertyType();
t = Nullable.GetUnderlyingType(t) ?? t;

//Coalesce to set the safe value using default(t) or the safe type.
safeValue = value == null ? default(t) : Convert.ChangeType(value, t);

我在代码中的许多地方使用了它,其中一个例子是我使用的helper方法,用于以类型安全的方式转换数据库值:

public static T GetValue<T>(this IDataReader dr, string fieldName)
{
    object value = dr[fieldName];

    Type t = typeof(T);
    t = Nullable.GetUnderlyingType(t) ?? t;

    return (value == null || DBNull.Value.Equals(value)) ? 
        default(T) : (T)Convert.ChangeType(value, t);
}

使用:

string field1 = dr.GetValue<string>("field1");
int? field2 = dr.GetValue<int?>("field2");
DateTime field3 = dr.GetValue<DateTime>("field3");

I wrote a series of blog posts including this at http://www.endswithsaurus.com/2010_07_01_archive.html (Scroll down to the Addendum, @JohnMacintyre actually spotted the bug in my original code which led me down the same path you're on now). I have a couple of small modifications since that post that includes conversion of enum types also so if your property is an Enum you can still use the same method call. Just add a line in to check for enum types and you're off to the races using something like:

if (t.IsEnum)
    return (T)Enum.Parse(t, value);

通常情况下,您会进行一些错误检查或使用TryParse而不是Parse,但您已经了解了情况。

我也有类似的需求,而LukeH的回答为我指明了方向。我用这个通用函数来简化。

    public static Tout CopyValue<Tin, Tout>(Tin from, Tout toPrototype)
    {
        Type underlyingT = Nullable.GetUnderlyingType(typeof(Tout));
        if (underlyingT == null)
        { return (Tout)Convert.ChangeType(from, typeof(Tout)); }
        else
        { return (Tout)Convert.ChangeType(from, underlyingT); }
    }

用法是这样的:

        NotNullableDateProperty = CopyValue(NullableDateProperty, NotNullableDateProperty);

注意,第二个参数只是作为一个原型来显示函数如何强制转换返回值,因此它实际上不必是目标属性。这意味着你也可以这样做:

        DateTime? source = new DateTime(2015, 1, 1);
        var dest = CopyValue(source, (string)null);

我用这种方法代替了out因为你不能在属性中使用out。实际上,它可以使用属性和变量。如果需要,也可以创建重载来传递该类型。

我是这样做的

public static List<T> Convert<T>(this ExcelWorksheet worksheet) where T : new()
    {
        var result = new List<T>();
        int colCount = worksheet.Dimension.End.Column;  //get Column Count
        int rowCount = worksheet.Dimension.End.Row;

        for (int row = 2; row <= rowCount; row++)
        {
            var obj = new T();
            for (int col = 1; col <= colCount; col++)
            {

                var value = worksheet.Cells[row, col].Value?.ToString();
                PropertyInfo propertyInfo = obj.GetType().GetProperty(worksheet.Cells[1, col].Text);
                propertyInfo.SetValue(obj, Convert.ChangeType(value, Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType), null);

            }
            result.Add(obj);
        }

        return result;
    }

未经测试,但也许这样的东西会起作用:

string modelProperty = "Some Property Name";
string value = "Some Value";

var property = entity.GetType().GetProperty(modelProperty);
if (property != null)
{
    Type t = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;

    object safeValue = (value == null) ? null : Convert.ChangeType(value, t);

    property.SetValue(entity, safeValue, null);
}

这甚至适用于Nullable类型:

TypeConverter conv = TypeDescriptor.GetConverter(type);
return conv.ConvertFrom(value);

为了类型安全,您还应该在调用ConvertFrom()之前调用convl . canconvertfrom (type)方法。如果它返回false,您可以回退到ChangeType或其他类型。