我使用反射更新已对其进行更新并保存到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
类型的对象,它是MongoDoc
的派生类型,其中包含导致异常的public 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:
答案 0 :(得分:2)
我用这个修好了,感谢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访问器。
答案 1 :(得分:1)
尝试使用具有SetValue
参数的System.Reflection.BindingFlags
重载,并将其传递给BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.NonPublic
。
答案 2 :(得分:0)
问题在于,从派生类型的角度来看,该属性没有setter。
您可以解决继承层次结构并获取在每种类型上声明的属性(使用DeclaredOnly BindingFlag以及Public和Instance),或检查属性是否由反射类型声明,如果没有再次获取它来自物业信息的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);
}
答案 3 :(得分:0)
问题可能出在下一个问题:
您正在使用汽车房产
public uint Revision { get; private set; }
其中通过默认类型int执行装箱/拆箱操作。
所以,在这里你应该明确地转换为uint类型。
您可以在下一个代码段中找到类似的问题:
byte b1 = 4;
byte b2 = 5;
byte sum = b1 + b2;
这将引发异常,因为没有为“+”运算符声明过载。 此片段实际上通过默认类型int演示了装箱/拆箱操作的问题。