TypeDescriptor.GetProperties (thisType) aux propriétés retour, qui sont en écriture seule

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

Question

Je suis en train d'obtenir toutes les propriétés d'un type, mais en utilisant TypeDescriptor.GetProperties (thisType) ne peut me fournir des propriétés, qui a à la fois compositeur et un getter. Je propriétés en écriture seule. Y at-il un moyen de récupérer une PropertyDescriptorCollection y compris ceux?

/ Asger

Était-ce utile?

La solution

propriétés en écriture seule sont une bête rare et n'existent pas dans l'espace System.ComponentModel / PropertyDescriptor. PropertyDescriptors sont conçus pour être lisibles. Je pourrais probablement pirater HyperDescriptor à calez propriétés en écriture seule, mais ce serait un hack -. Et il aurait sans doute de lever des exceptions pour get, ce qui pourrait avoir un impact code d'appel tout à fait un peu

En aparté; Je conseille généralement contre propriétés en écriture seulement; l'exemple livre de texte que les gens débitent des mots de passe est (public string Password {private get;set;}) - j'aurais bien plutôt une méthode de void SetPassword(string newPassword) ...

Qu'est-ce que vous voulez réellement faire? Il existe une gamme d'options ici, très réalisable:

  • utilisation seule réflexion (lent, peut-être pas une option)
  • utilisation Delegate.CreateDelegate (très facile)
  • utilisation Expression.Compile ( petit plus difficile, mais pas beaucoup)
  • utilisation Reflection.Emit (assez difficile)
  • shim propriétés en écriture seule dans PropertyDescriptor (assez difficile)

Si vous me le faire savoir ce que vous voulez réellement faire (plutôt que la façon dont vous essayez actuellement de le faire), je pourrais être en mesure d'aider plus.

À titre d'exemple à l'aide Delegate.CreateDelegate (notez que vous voulez cacher quelque part le délégué et réutilisez-le bon nombre de fois):

modifié pour montrer comment le faire si vous ne connaissez pas les types spécifiques à l'exécution

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

Ou bien en utilisant l'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();
    }
}

Autres conseils

Utilisez System.Type.GetProperties() à la place, qui renvoie toutes les propriétés. Notez que cela retourne un PropertyInfo[] au lieu d'un PropertyDescriptorCollection.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top