Pregunta ¿Cómo se encuentran solo las propiedades que tienen tanto getter como setter?


C #, .NET 3.5

Estoy tratando de obtener todas las propiedades de un objeto que tenga TANTO un captador como un colocador para la instancia. El código I pensamiento debería funcionar es

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

Sin embargo, los resultados incluyen una propiedad que no tiene un setter. Para darle una idea simple de mi estructura de herencia que podría estar afectando esto (aunque no sé cómo):

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
}

Termino con el siguiente error cuando trabajo con Name:

System.ArgumentException: Property set method not found.

EDITAR: Me gustaría saber por qué esto no trabajo, así como lo que debería hacer para no obtener el error.


31
2017-11-19 16:25


origen


Respuestas:


Llamada GetGetMethod y GetSetMethod en la propiedad - si ambos resultados no son nulos, estás ahí :)

(Las versiones sin parámetros solo devuelven métodos públicos; hay una sobrecarga con un parámetro booleano para especificar si desea o no métodos no públicos).


35
2017-11-19 16:31



Usted puede verificar PropertyInfo.CanRead y PropertyInfo.CanWrite propiedades.


32
2017-07-22 09:35



qué tal si...

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

28
2018-01-02 00:32



Esto no se supone que funcione.

Ver definición de GetProperties en msdn para lo cual está permitido:

El seguimiento BindingFlags los indicadores de filtro se pueden usar para definir qué tipos anidados incluir en la búsqueda:

* 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.

O puedes ver la definición de GetProperty/SetProperty en msdn, el cual establece que:

GetProperty = Especifica que el valor de la propiedad especificada   debe ser devuelto

SetProperty = Especifica que el valor de la propiedad especificada   debe establecerse. Para las propiedades COM, especificar este indicador de enlace es   equivalente a especificar PutDispProperty y PutRefDispProperty.


1
2017-11-19 16:56



Para hacerlo un poco más genérico, puede heredar de 'ObjectWithDefaultValues' y / o llamar al método de extensión obj.SetDefaultValues ​​(). Ambos se enumeran a continuación.

Código:

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

0
2018-02-08 00:35