TypeDescriptor.GetProperties (thisType) para devolver las propiedades, que son de sólo escritura

StackOverflow https://stackoverflow.com/questions/772107

Pregunta

Estoy tratando de obtener todas las propiedades de un tipo, pero utilizando TypeDescriptor.GetProperties (thisType) sólo me va a suministrar con propiedades, que tiene tanto setter y un captador. Tengo propiedades de sólo escritura. ¿Hay una manera de recuperar una PropertyDescriptorCollection incluyendo aquellos?

/ Asger

¿Fue útil?

Solución

propiedades de sólo escritura son una bestia rara, y no existen en el espacio System.ComponentModel / PropertyDescriptor. PropertyDescriptors están diseñados para ser legible. Probablemente podría piratear HyperDescriptor a calzar las propiedades de sólo escritura, pero sería un truco -. Y es de suponer que lanzar excepciones para get, lo que podría afectar código de llamada un poco

Como un aparte; Yo por lo general aconsejo propiedades sólo escritura; el ejemplo de libro de texto que las personas sacan a relucir es contraseñas (public string Password {private get;set;}) - Prefiero tener un método void SetPassword(string newPassword) ...

¿Qué es lo que realmente quiere hacer? Hay una serie de opciones aquí, todo muy alcanzable:

  • Uso de la reflexión solo (lenta, tal vez no es una opción)
  • Uso Delegate.CreateDelegate (muy fácil)
  • Uso Expression.Compile (a poco más difícil, pero no mucho)
  • Uso Reflection.Emit (muy duro)
  • propiedades de sólo escritura calza en PropertyDescriptor (muy duro)

Si usted me deja saber lo que realmente quiere hacer (en lugar de la forma en que actualmente está tratando de hacerlo), que podría ser capaz de ayudar más.

A modo de ejemplo usando Delegate.CreateDelegate (tenga en cuenta que se quiere esconder el delegado en algún lugar y volver a usarlo muchas veces):

editado para mostrar cómo hacerlo si no conoce los tipos específicos en tiempo de ejecución

using System;
using System.Reflection;

class Foo
{
    public string Bar { private get; set; }
    public override string ToString()
    {
        return Bar; // to prove working
    }
}
static class Program
{
    static void Main()
    {
        ISetter setter = Setter.Create(typeof(Foo), "Bar");
        Foo foo = new Foo();
        setter.SetValue(foo, "abc");
        string s = foo.ToString(); // prove working
    }
}
public interface ISetter {
    void SetValue(object target, object value);
}
public static class Setter
{
    public static ISetter Create(Type type, string propertyName)
    {
        if (type == null) throw new ArgumentNullException("type");
        if (propertyName == null) throw new ArgumentNullException("propertyName");
        return Create(type.GetProperty(propertyName));
    }
    public static ISetter Create(PropertyInfo property)
    {
        if(property == null) throw new ArgumentNullException("property");
        if (!property.CanWrite) throw new InvalidOperationException("Property cannot be written");
        Type type = typeof(TypedSetter<,>).MakeGenericType(
                property.ReflectedType, property.PropertyType);
        return (ISetter) Activator.CreateInstance(
            type, property.GetSetMethod());
    }
}

public class TypedSetter<TTarget, TValue> : ISetter {
    private readonly Action<TTarget, TValue> setter;
    public TypedSetter(MethodInfo method) {
        setter = (Action<TTarget, TValue>)Delegate.CreateDelegate(
            typeof(Action<TTarget, TValue>), method);
    }
    void ISetter.SetValue(object target, object value) {
        setter((TTarget)target, (TValue)value);
    }
    public void SetValue(TTarget target, TValue value) {
        setter(target, value);
    }
}

O, alternativamente, mediante la API Expression (.NET 3.5):

using System;
using System.Linq.Expressions;
using System.Reflection;

class Foo
{
    public string Bar { private get; set; }
    public override string ToString()
    {
        return Bar; // to prove working
    }
}
static class Program
{
    static void Main()
    {
        Action<object,object> setter = Setter.Create(typeof(Foo), "Bar");
        Foo foo = new Foo();
        setter(foo, "abc");
        string s = foo.ToString();
    }
}

public static class Setter
{
    public static Action<object,object> Create(Type type, string propertyName)
    {
        if (type == null) throw new ArgumentNullException("type");
        if (propertyName == null) throw new ArgumentNullException("propertyName");
        return Create(type.GetProperty(propertyName));
    }
    public static Action<object,object> Create(PropertyInfo property)
    {
        if(property == null) throw new ArgumentNullException("property");
        if (!property.CanWrite) throw new InvalidOperationException("Property cannot be written");

        var objParam = Expression.Parameter(typeof(object), "obj");
        var valueParam = Expression.Parameter(typeof(object), "value");
        var body = Expression.Call(
            Expression.Convert(objParam, property.ReflectedType),
            property.GetSetMethod(),
            Expression.Convert(valueParam, property.PropertyType));
        return Expression.Lambda<Action<object, object>>(
            body, objParam, valueParam).Compile();
    }
}

Otros consejos

System.Type.GetProperties() en cambio, que devuelve todas las propiedades. Observe que este devuelve un PropertyInfo[] en lugar de un PropertyDescriptorCollection.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top