你怎么只找到同时拥有getter和setter的属性?

时间:2008-11-19 16:25:18

标签: c# .net reflection

C#,. NET 3.5

我试图获取一个对象的所有属性,它们同时具有实例的getter和setter。我认为应该运行的代码是

PropertyInfo[] infos = source.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty | BindingFlags.GetProperty);

但是,结果包括没有setter的属性。为了简单介绍一下可能影响这个的继承结构(虽然我不知道如何):

public interface IModel
{
    string Name { get; }
}

public class BaseModel<TType> : IModel
{
    public virtual string Name { get { return "Foo"; } }

    public void ReflectionCopyTo(TType target)
    {
        PropertyInfo[] infos = this.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty | BindingFlags.GetProperty);
        foreach (PropertyInfo info in infos)
            info.SetValue(target, info.GetValue(this, null), null);
    }
}

public class Child : BaseModel<Child>
{
    // I do nothing to override the Name property here
}

使用名称时,我最终得到以下错误:

System.ArgumentException: Property set method not found.

编辑:我想知道为什么工作,以及我应该做些什么来避免错误。

5 个答案:

答案 0 :(得分:37)

在属性上调用GetGetMethodGetSetMethod - 如果两个结果都是非空的,那么你就在那里:)

(无参数版本只返回公共方法;有一个带布尔参数的重载,用于指定是否还需要非公共方法。)

答案 1 :(得分:32)

您可以查看PropertyInfo.CanReadPropertyInfo.CanWrite属性。

答案 2 :(得分:28)

怎么样......

var qry = typeof(Foo).GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Where(p => p.CanRead && p.CanWrite);

答案 3 :(得分:1)

这不应该起作用。

请参阅msdn上允许的GetProperties定义:

以下BindingFlags过滤器标志可用于定义要包含在搜索中的嵌套类型:

* You must specify either BindingFlags.Instance or BindingFlags.Static in order to get a return.
* Specify BindingFlags.Public to include public properties in the search.
* Specify BindingFlags.NonPublic to include non-public properties (that is, private and protected members) in the search.
* Specify BindingFlags.FlattenHierarchy to include static properties up the hierarchy.

或者您可以在msdn中看到GetProperty / SetProperty的定义,其中指出:

  

GetProperty =指定指定属性的值   应该退还。

     

SetProperty =指定指定属性的值   应该设定。对于COM属性,指定此绑定标志是   相当于指定PutDispProperty和PutRefDispProperty。

答案 4 :(得分:0)

为了使它更通用,你可以继承'ObjectWithDefaultValues'和/或调用obj.SetDefaultValues()扩展方法。两者都列在下面。

代码:

public abstract class ObjectWithDefaultValues : object {

    public ObjectWithDefaultValues () : this(true){
    }

    public ObjectWithDefaultValues (bool setDefaultValues) {
        if (setDefaultValues)
            this.SetDefaultValues();    
    }
}

public static class ObjectExtensions {

    public static void SetDefaultValues(this object obj) {
        foreach (FieldInfo f in obj.GetType().GetFields(BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetField)) {
            foreach (Attribute attr in f.GetCustomAttributes(true)) {
                if (attr is DefaultValueAttribute) {
                    var dv = (DefaultValueAttribute)attr;
                    f.SetValue(obj, dv.Value);
                }
            }
        }

        foreach (var p in obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty)) {
            if (p.GetIndexParameters().Length == 0) {
                foreach (Attribute attr in p.GetCustomAttributes(true)) {
                    if (attr is DefaultValueAttribute) {
                        var dv = (DefaultValueAttribute)attr;
                        p.SetValue(obj, dv.Value, null);
                    }
                }
            }
        }
    }
}