【问题标题】:C# Reflection SetValue() can not find set accessorC# 反射 SetValue() 找不到集合访问器
【发布时间】:2012-09-14 20:58:25
【问题描述】:

我使用反射来更新已对其进行更新并保存到 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: 

【问题讨论】:

  • 您的属性是否都有private set 访问器?
  • 是的,这让我感到困惑,我想“哦,也许是因为属性集访问器是私有的”,但是我的其他属性也有私有集访问器,而且它们被写入就好了,我读了一些该反射不关心属性访问器级别,只要属性本身是公共的,它就可以访问它。
  • Revision 属性是 Product 类还是 MongoDoc 类?
  • MongoDoc 类,这就是我在问题中试图说的,但不是很清楚抱歉。但是 updateSelf 方法在 MongoDoc 类中,参数是一个 mongoDoc,this 显然
  • 不需要什么特别的。究竟是什么异常?包括 InnerException。

标签: c# reflection


【解决方案1】:

我解决了这个问题,感谢 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 访问器。

【讨论】:

  • 必须使用基本类型的原因是因为 set 访问器是私有的。使用class A {}; class B : A {},B 无法访问 A 的私有成员,因此反射也不允许您通过类型 B 访问 A 的私有成员。
  • 确实,这正是我的情况。我得到了属性的 DeclaringType 并且能够设置该属性。 var propertyInfo = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty).FirstOrDefault(); var p2 = propertyInfo.DeclaringType.GetProperty(propertyInfo.Name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty); p2.SetValue(instance, messageHandler, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty, null, null, null);
【解决方案2】:

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

【讨论】:

  • i.SetValue(this, newValue, System.Reflection.BindingFlags.SetProperty | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic, null, null, null); 尝试过,但无济于事,出现完全相同的问题
【解决方案3】:

问题在于,从派生类型的角度来看,该属性没有设置器。

您可以解决此问题,遍历继承层次结构并获取在每种类型上声明的属性(使用 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);
    }

【讨论】:

  • 为什么不总是使用 property.DeclaringType?
  • 您的意思不是检查它是否与 property.ReflectedType 不同?它们真的是等价的。
  • 我的意思是为什么要使用条件运算符?说var actualProperty = property.DeclaringType.GetProperty(property.Name);var actualProperty = property.DeclaringType != property.ReflectedType ? property.DeclaringType.GetProperty(property.Name) : property; 更简单。
  • 是的,知道了。结果是一样的。
【解决方案4】:

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

你可以通过下一个sn-p找到类似的问题:

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

这将引发异常,因为没有为“+”运算符声明重载。 这个 sn-p 实际上演示了通过默认类型 int 进行装箱/拆箱操作的问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多