3

リフレクションを使用して、更新が行われ、mongodbに保存されたオブジェクトを更新します

    private void updateSelf(MongoDoc newDoc)
    {
        Type type = this.GetType();
        foreach (var i in type.GetProperties())
        {
            if (i.GetCustomAttributes(false).Any(x => x is MongoDB.Bson.Serialization.Attributes.BsonIgnoreAttribute)) continue;
            Object oldValue = i.GetValue(this, null);
            Object newValue = i.GetValue(newDoc, null);
            if (!Object.Equals(oldValue, newValue) && !((oldValue == null) && (newValue == null)))
            {
                i.SetValue(this, newValue, null);
            }
        }
    }

これはほとんどの部分で機能していますが、i.SetValue(this, newValue, null);このプロパティを更新しようとすると例外がスローされます。

public uint Revision { get; private set; }

これは、例外を引き起こしているプロパティを含むProduct派生型である型のオブジェクトを更新しようとしています。これは他のすべてのプロパティで機能するため、これが原因であるかどうかはわかりません。これだけがスローされ、例外が発生します。どんな助けでも大歓迎MongoDocpublic uint Revision { get; private set; }Property set Method not found

アップデート:

私は以下の答えを試しました:

i.SetValue(this, newValue, System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic, null, null, null);

ただし、残念ながらまったく同じ結果であり、Revisionプロパティで例外がスローされます。

アップデート:

例外:

System.ArgumentException was unhandled
  Message=Property set method not found.
  Source=mscorlib
  StackTrace:
       at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
       at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, Object[] index)
       at Flo.Client.Docs.MongoDoc.updateSelf(MongoDoc newDoc) in F:\Flo\Flo.Client\Docs\MongoDoc.cs:line 162
       at Flo.Client.Docs.MongoDoc.UpdateToMongo(MongoDoc newDoc) in F:\Flo\Flo.Client\Docs\MongoDoc.cs:line 120
       at Flo.Client.Docs.Product.EditProduct(String Name, Nullable`1 State) in F:\Flo\Flo.Client\Docs\Product.cs:line 89
       at Flo.Client.Program.Main() in F:\Flo\Flo.Client\Program.cs:line 26
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
4

4 に答える 4

2

解決策を得るのに十分な別の質問を教えてくれたDylanMeadorのおかげで、これで修正しました。

    private void updateSelf(MongoDoc newDoc, Type type)
    {
        foreach (var i in type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public))
        {
            if (i.GetCustomAttributes(false).Any(x => x is MongoDB.Bson.Serialization.Attributes.BsonIgnoreAttribute)) continue;
            Object oldValue = i.GetValue(this, null);
            Object newValue = i.GetValue(newDoc, null);
            if (!Object.Equals(oldValue, newValue) && !((oldValue == null) && (newValue == null)))
            {
                i.SetValue(this, newValue, null);
            }
        }
        Type baseType = type.BaseType;
        if (baseType != null)
        {
            this.updateSelf(newDoc, baseType);
        }
    }

その特定のプロパティにsetアクセサーを使用するには、Typeを基本クラスtypeに明示的に設定する必要があるようです。

于 2012-09-14T22:08:07.820 に答える
1

SetValueパラメータを持つのオーバーロードを使用してSystem.Reflection.BindingFlags、値を渡してみてくださいBindingFlags.SetProperty | BindingFlags.Public | BindingFlags.NonPublic

于 2012-09-14T21:09:18.860 に答える
0

問題は、派生型の観点から、プロパティのセッターがないことです。

この回避策として、継承階層をたどり、各タイプで宣言されたプロパティを取得するか(DeclaredOnly BindingFlagをPublicおよびInstanceとともに使用して)、プロパティがリフレクションタイプによって宣言されているかどうかを確認し、そうでない場合はプロパティから再度取得します。 infoのDeclaringType。

前者の場合はネストされたループを作成できますが、後者の場合は次のようになります。

    foreach (var property in p.GetType().GetProperties())
    {
        var actualProperty = property.DeclaringType != property.ReflectedType ? property.DeclaringType.GetProperty(property.Name) : property;
        actualProperty.SetValue(p, newValue, null);
    }
于 2012-09-14T22:08:19.707 に答える
0

おそらく次の問題が発生する可能性があり ます。デフォルトのタイプintを介してボックス化/ボックス化解除操作を実行する
autoプロパティを使用しています。
public uint Revision { get; private set; }したがって、ここでは明示的にuintタイプにキャストする必要があります。

次のスニペットで同様の問題を見つけることができます:

byte b1 = 4;  
byte b2 = 5;  
byte sum = b1 + b2;

「+」演算子にはオーバーロードが宣言されていないため、これにより例外が発生します。このスニペットは、実際には、デフォルトの型intを使用したボックス化/アンボックス化操作の問題を示しています。

于 2012-09-14T23:35:02.390 に答える