C#反射的SetValue()无法找到set访问(C# Reflection SetValue()

2019-09-22 10:47发布

我使用反射来更新他们不得不他们所做的更新,并保存到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; } public uint Revision { get; private set; } 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);

但不幸的是完全相同的结果,但它仍然抛出的修订财产除外。

更新:

例外:

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: 

Answer 1:

我用这个固定,由于迪伦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);
        }
    }

它看起来像需要明确设定为基类,以便使用set访问该特定属性的类型。



Answer 2:

尝试使用过载SetValue有一个System.Reflection.BindingFlags参数,并通过它的值BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.NonPublic BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.NonPublic BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.NonPublic



Answer 3:

的问题是,从视派生类型的点没有为属性没有setter。

您可以解决此散步的继承层次和获得(与公共和实例使用DeclaredOnly BindingFlag,一起)在每个类型中声明的属性,或者检查属性是否被反射型宣称,如果不从属性再次得到它信息的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);
    }


Answer 4:

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

你可以找到旁边片段类似的问题:

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

因为没有过载被宣布为“+”操作符这将引发异常。 这段代码实际上表明通过默认类型为int装箱/拆箱操作的问题。



文章来源: C# Reflection SetValue() can not find set accessor
标签: c# reflection