C#Reflection SetValue()找不到set accessor

我使用reflection来更新已对其进行更新并保存到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); 尝试更新此属性时抛出exception:

 public uint Revision { get; private set; } 

这是尝试更新Product类型的对象,它是MongoDoc的派生类型,其中包含属性public uint Revision { get; private set; } public uint Revision { get; private set; } public uint Revision { get; private set; }导致exceptionProperty set Method not found我不确定是什么导致这个因为它适用于我的所有其他属性,只有这一个抛出和exception。 任何帮助非常感谢

更新:

我尝试过以下答案:

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

但遗憾的是完全相同的结果,它仍然会在Revision属性上抛出exception。

更新:

例外:

 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: 

我用这个修好了,感谢Dylan Meador给我指的另一个问题让我足以得到解决方案:

  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); } } 

看起来需要将Type显式设置为基类类型,以便为该特定属性使用set访问器。

尝试使用具有System.Reflection.BindingFlags参数的SetValue的重载,并将其传递给BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.NonPublic BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.NonPublic BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.NonPublic

问题是从派生类型的角度来看,没有属性的setter。

您可以解决inheritance层次结构并获取在每种类型上声明的属性(使用DeclaredOnly BindingFlag以及Public和Instance),或检查属性是否由reflection类型声明,如果不是从属性再次获取它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); } 

可能问题可能出在下一个问题:
您正在使用自动财产
public uint Revision { get; private set; } 通过默认类型int执行装箱/拆箱操作。 所以,在这里你应该明确地转换为uint类型。

您可以在下一个代码段中找到类似的问题:

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

这将引发exception,因为没有为“+”运算符声明过载。 此片段实际上通过默认类型int演示了装箱/取消装箱操作的问题。