如何查找具有getter和setter的属性?

41

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
}

在使用 Name 时,我遇到了以下错误:

System.ArgumentException: Property set method not found.

编辑:我想知道为什么这个不起作用,以及我应该做什么才能避免出错。

5个回答

48

调用属性的GetGetMethodGetSetMethod方法 - 如果两个结果都不为空,则成功 :)

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


4
为什么 BindingFlags.SetProperty 没有进行过滤呢?我原以为它应该会这样做。 - Matt
15
@Matt: 因为BindingFlags.SetProperty和BindingFlags.SetProperty不用于查找,它们在其他情况下使用,Get Properties() 方法会忽略这些标志。尝试不使用它们,您将得到相同的结果。请参阅支持的标志:http://msdn.microsoft.com/en-us/library/kyaxdd3x.aspx - Pop Catalin

42
您可以检查 PropertyInfo.CanReadPropertyInfo.CanWrite 属性。

7
请注意,即使getter/setter不是公共的,它们也会返回true。这些属性只检查getter/setter的存在。 - Sebastian Krysmanski

39

怎么样……

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

1

这不应该起作用。

请参阅msdnGetProperties的定义,了解允许使用哪些内容:

以下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。


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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接