0

編集: LoveMeSomeCode からの回答に基づいて、この問題は VB.Net でのみ発生すると思います。

変更されたプロパティの古い値を辞書に保存し、元に戻す必要があるときにリフレクションを介して設定することにより、クラスを以前の状態に戻そうとしています。古い値が Nothing (null) の場合、プロパティを設定しようとすると null 参照例外が発生するという問題があります。これが私が試したことです。

次のような for each ループを想定します。

For Each pair As KeyValuePair(Of String, Object) In myOldValues
...
Next

方法 1:

CallByName(Me, pair.Key, CallType.Set, pair.Value)

方法 2:

Me.GetType().InvokeMember(pair.Key, Reflection.BindingFlags.SetProperty, Nothing, Me, pair.Value)

方法 3:

Dim propInfo As System.Reflection.PropertyInfo = Me.GetType.GetProperty(pair.Key)
propInfo.SetValue(Me, Convert.ChangeType(pair.Value, propInfo.PropertyType), Nothing)

これらのメソッドごとに、pair.Value が null の場合に null 参照例外が発生します。セッターは null 値を保持できます (多くの場合、プロパティは文字列です)。何が間違っているのか、どうすれば回避できますか?

編集: null を直接渡すと、各メソッドは失敗します。

編集:誰かに役立つ場合のスタックトレースは次のとおりです。

方法 1 System.NullReferenceException: オブジェクト参照がオブジェクトのインスタンスに設定されていません。Microsoft.VisualBasic.CompilerServices.Symbols.Container.InvokeMethod (メソッド TargetProcedure、オブジェクト [] 引数、ブール値 [] CopyBack、BindingFlags フラグ) で Microsoft.VisualBasic.CompilerServices.NewLateBinding.LateSet (オブジェクト インスタンス、型の種類、文字列 MemberName、オブジェクト[] Arguments, String[] ArgumentNames, Type[] TypeArguments, Boolean OptimisticSet, Boolean RValueBase, CallType CallType) Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(Object Instance, String MethodName, CallType UseCallType, Object[] Arguments) at myProject myfileの .Presenter.CustomerDetailPresenter.RevertCustomer() : 378 行目

方法 2 System.Reflection.TargetInvocationException: 呼び出しのターゲットによって例外がスローされました。---> System.NullReferenceException: オブジェクト参照がオブジェクトのインスタンスに設定されていません。私のプロジェクトで.Presenter.CustomerDetailPresenter.set_City(String value) --- 内部例外スタック トレースの終了 --- System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) at System.RuntimeMethodHandle .InvokeMethodFast (オブジェクト ターゲット、オブジェクト [] 引数、シグネチャ sig、MethodAttributes methodAttributes、RuntimeTypeHandle typeOwner) で System.Reflection.RuntimeMethodInfo.Invoke(オブジェクト obj、BindingFlags invokeAttr、バインダー バインダー、オブジェクト [] パラメーター、CultureInfo カルチャ、ブール値の skipVisibilityChecks) でSystem.Reflection.RuntimeMethodInfo.Invoke(オブジェクト obj、BindingFlags invokeAttr、バインダー バインダー、Object[] パラメーター、CultureInfo カルチャ) System.RuntimeType.InvokeMember(文字列名、BindingFlags bindingFlags、バインダー バインダー、System.Type.InvokeMember(文字列名、BindingFlags invokeAttr、バインダー バインダー、オブジェクト ターゲット、Object[] args)myProject .Presenter.CustomerDetailPresenter.RevertCustomer()

方法 3 System.Reflection.TargetInvocationException: 呼び出しのターゲットによって例外がスローされました。---> System.NullReferenceException: オブジェクト参照がオブジェクトのインスタンスに設定されていません。私のプロジェクトで.Presenter.CustomerDetailPresenter.set_City(String value) --- 内部例外スタック トレースの終了 --- System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) at System.RuntimeMethodHandle System.Reflection.RuntimeMethodInfo.Invoke(Object obj、BindingFlags invokeAttr、Binder バインダー、Object[] パラメーター、CultureInfo カルチャ、ブール値の skipVisibilityChecks) での .InvokeMethodFast(Object ターゲット、Object[] 引数、シグネチャ sig、MethodAttributes methodAttributes、RuntimeTypeHandle typeOwner)

System.Reflection.RuntimeMethodInfo.Invoke (オブジェクト obj、BindingFlags invokeAttr、バインダー バインダー、Object [] パラメーター、CultureInfo カルチャ) で System.RuntimeType.InvokeMember (文字列名、BindingFlags bindingFlags、バインダー バインダー、オブジェクト ターゲット、Object [] providedArgs、 ParameterModifier[] 修飾子、CultureInfo カルチャ、String[] namedParams) の System.Type.InvokeMember(String 名、BindingFlags invokeAttr、Binder バインダー、オブジェクト ターゲット、Object[] args) at myProject .Presenter.CustomerDetailPresenter.RevertCustomer()

4

3 に答える 3

3

2 番目と 3 番目のオプションのスタック トレースでこれが見られるという事実

System.NullReferenceException: オブジェクト参照がオブジェクトのインスタンスに設定されていません。myProject.Presenter.CustomerDetailPresenter.set_City (文字列値) で

null 値を処理していない CustomerDetailPresenter.City プロパティ セッターに何かがあると思います。プロパティセッターの実装は何ですか? 失敗する可能性のある検証または監査コードはありますか?

2009 年 3 月 24 日更新: VB での簡単なテストで、このコードは意図したとおりに動作します。あなたが説明するシナリオをキャプチャしようとしました。

プロパティが設定されている私のテストクラス(一部):

Public Class MyObject

    Private mId As Integer
    Private mName As String
    Private mDOB As Date
     .......
     .......
    Public Property Name() As String
        Get
            Return mName
        End Get
        Set(ByVal Value As String)
            mName = Value
        End Set
    End Property

プロパティ名、値、および型を保持する PropertyState クラスを作成しました。プロパティを動的に設定するコードは次のとおりです。

Private Sub SetValues()
        'get object that we are working with
        Dim ty As Type = mObjectInstance.GetType

        'create our property name/value info
        Dim info As New PropertyState
        With info
            .PropName = "Name"
            .OriginalValue = Nothing
            .ValueType = GetType(String)
        End With

        'now use reflection to set value on object
        Dim prop As PropertyInfo = ty.GetProperty("Name", BindingFlags.Instance Or BindingFlags.Public)
        'use Convert.ChangeType to duplicate problem scenario
        Dim newValue = Convert.ChangeType(Nothing, GetType(String))
        'prop.SetValue(mObjectInstance, newValue, BindingFlags.Instance Or BindingFlags.Public, Nothing, Nothing, Globalization.CultureInfo.CurrentUICulture)
        prop.SetValue(mObjectInstance, Convert.ChangeType(info.OriginalValue, info.ValueType), Nothing)

        DisplayValues(CType(mObjectInstance, MyObject))
    End Sub

SetValue メソッドの 2 つの異なるオーバーロードを使用しましたが、BindingFlags を明示的に設定しないと、リフレクションの問題が発生する場合があることがわかりました。ただし、この場合、両方のオーバーロードが正常に機能します。

それで、質問に投稿したスタックトレースを振り返ります。

System.NullReferenceException: オブジェクト参照がオブジェクトのインスタンスに設定されていません。myProject.Presenter.CustomerDetailPresenter.set_City (文字列値) で

set_City() セッターが例外をスローしているという事実は、メソッドが見つかり、正常に呼び出されたことを示しています。要求どおりに null (何もない) 値が渡されています。したがって、バグはリフレクションにあるのではなく、プロパティ セッターが呼び出された結果として何が起こっているかにあります。おそらく既にこれを試したことがあると思いますが、セッターにブレークポイントを設定するか、管理対象のすべての例外で中断するように IDE を設定して、実際の原因を把握できるかどうかを確認してください。または、格納されたプロパティ情報の状態は期待どおりですか? 名前、型、値はすべて同期していますか?

お役に立てれば。

于 2009-03-17T19:04:01.937 に答える
0

これは VB.NET ではなく C# ですが、次のように動作するようです。

private Dictionary<string, object> MemoryValues = new Dictionary<string, object>();

        public void Store()
        {
            foreach (PropertyInfo info in this.GetType().GetProperties())
            {
                if (MemoryValues.ContainsKey(info.Name))
                    MemoryValues[info.Name] = info.GetValue(this, null);
                else
                    MemoryValues.Add(info.Name, info.GetValue(this, null));
            }
        }

        public void Recall()
        {
            foreach (PropertyInfo info in this.GetType().GetProperties())
            {
                info.SetValue(this, MemoryValues[info.Name], null);
            }
        }

プロパティを設定して Store() を呼び出すと、辞書に保存されます。次に、それらを変更して Recall() を呼び出すと、それらが復元されます。少なくとも文字列に対してはnullになるようです。基本クラスに入れるのに適したセットのようです。

于 2009-01-23T15:22:15.730 に答える