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 許容型であるプロパティ型の特殊なケースを追加し、値が null または空の場合は、プロパティ値を null に設定します。

于 2012-08-22T13:52:30.537 に答える