2

我正在使用下面的代码来设置一个类的值,这个类的一些值string decimal decimal? int?等等。

我有一个字段列表 - 其值为字符串,.net 抛出以下异常:

System.InvalidCastException : Invalid cast from 'System.String' to 'System.Nullable`1[[System.Decimal, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.
at System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider)
at System.String.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)
at Surventrix.Domain.Model.Entities.StatisticalData.UpdateStatisticalData(ReportCommit commit, ILogProvider log) in StatisticalData.cs: line 591
at Surventrix.Tests.Stats.StatsTest.CreateStatsFromCommit() in StatsTest.cs: line 32 

我的代码是:

    public void UpdateStatisticalData(ReportCommit commit, ILogProvider log)
    {
        var fields = commit.CurrentFieldList.ToList();

        var properties = typeof(StatisticalData).GetProperties();

        foreach (var p in properties)
        {
            log.LogMessage("what my name: {0}", p.Name);
            // If not writable then cannot null it; if not readable then cannot check it's value
            if (!p.CanWrite || !p.CanRead) { continue; }

            var mget = p.GetGetMethod(false);
            var mset = p.GetSetMethod(false);

            // Get and set methods have to be public
            if (mget == null) { continue; }
            if (mset == null) { continue; }


            var val = fields.SingleOrDefault(x => p.Name == x.Name);

            if (val == null) continue;

            //field.value is stored as a string
            if (string.IsNullOrEmpty(val.Value)) continue;

            log.LogMessage("set: {0} ----> {1}", p.Name, val.Value);

            var typedVal = Convert.ChangeType(val.Value, p.PropertyType);

            p.SetValue(this, typedVal, null);
        }

    }

问题:我怎样才能修复我的代码以便不抛出这个异常,我真的不明白为什么这里会抛出这个异常......

更新 - 日志结果*

what my name: StatisticalDataID
what my name: OfficeDistanceFromProperty
what my name: OfficeAddress1
set: OfficeAddress1 ----> North Warwickshire House
what my name: OfficeAddress2
set: OfficeAddress2 ----> 92 Wheat Street
what my name: OfficeAddress3
what my name: OfficeCounty
what my name: OfficeTown
set: OfficeTown ----> Nuneaton
what my name: OfficePostcode
set: OfficePostcode ----> CV11 4BH
what my name: ResidentialInternalFloorArea
what my name: ValuationCalculationSqFtAssumed
what my name: SubjectPropertyAddress1
set: SubjectPropertyAddress1 ----> 323 Stanton road
what my name: SubjectPropertyAddress2
set: SubjectPropertyAddress2 ----> cbvcb
what my name: SubjectPropertyAddress3
set: SubjectPropertyAddress3 ----> vcbc
what my name: SubjectPropertyTown
set: SubjectPropertyTown ----> Coventry
what my name: SubjectPropertyCounty
set: SubjectPropertyCounty ----> bcbvc
what my name: SubjectPropertyPostCode
set: SubjectPropertyPostCode ----> CV1 4HH
what my name: OccupierName
set: OccupierName ----> Mr Peters
what my name: AdvanceAmount
set: AdvanceAmount ----> 0

更新- 我已经更新了你的代码@Jon,我正在调用这样的方法:

            var typedVal = NullableSafeChangeType(val.Value, p.PropertyType);

            if (!string.IsNullOrEmpty(val.Value))
                p.SetValue(this, typedVal, null);

在以下位置引发错误:

            _log.LogMessage("error is here ---> {0}", input);
            return input == null || input == "" ? null : Convert.ChangeType(input, underlyingType);

输入是任何有效的字符串,type(System.String)

4

3 回答 3

5

它与设置属性无关,与更改类型有关。这是一个简短但完整的示例,演示了该问题:

using System;

class Test
{
    static void Main()
    {
        object converted = Convert.ChangeType("10", typeof(int?));
        Console.WriteLine(converted);
    }
}

基本Convert.ChangeType不支持Nullable<T>。你必须自己处理。您可以编写一个检测目标类型为 的方法Nullable<T>,并返回 null(如果原始字符串值为 null 或对空字符串的引用)或将其转换为基础类型的结果。

编辑:例如(完全未经测试):

static object NullableSafeChangeType(string input, Type type)
{
    Type underlyingType = Nullable.GetUnderlyingType(type);
    if (underlyingType == null) // Non-nullable; convert directly
    {
        return Convert.ChangeType(input, type);
    }
    else
    {
        return input == null || input == "" ? null
            : Convert.ChangeType(input, underlyingType);
    }
}
于 2012-08-22T13:50:09.607 回答
0

我认为您需要以下方法:

    private static T Convert<T>(string input)
    {
        if (input == null) throw new ArgumentNullException("input");
        var converter = TypeDescriptor.GetConverter(typeof(T));
        if (input.Is(typeof(T)))
        {
            try
            {
                return (T)converter.ConvertFromString(input);
            }
            catch (NotSupportedException notSupportedException)
            {
                Console.WriteLine(notSupportedException);
            }
        }
        return default(T);
    }

使用:

                try
                {
                    // If Value is not a string => Convert over Generic Method
                    MethodInfo method = typeof(whereConvertImplemented).GetMethod("Convert", BindingFlags.NonPublic | BindingFlags.Static);
                    MethodInfo generic = method.MakeGenericMethod(property.PropertyType);
                    var value = generic.Invoke(this, new object[] { propvalue });
                    property.SetValue(this, value, null);
                }
                catch
                {

                }

希望对你有帮助 :)

问候

于 2012-08-22T13:51:33.273 回答
0

这条线

var typedVal = Convert.ChangeType(val.Value, p.PropertyType);

不适用于可为空的类型。您为可空类型的属性类型添加了一个特殊情况,如果值为 null 或为空,则将属性值设置为 null。

于 2012-08-22T13:52:30.537 回答