TypeDescriptor.GetProperties (thisType) per restituire le proprietà che sono in sola scrittura

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

Domanda

Sto cercando di ottenere tutte le proprietà di un tipo, ma utilizzando TypeDescriptor.GetProperties (thisType) si mi fornire soltanto con proprietà, che ha sia setter e un getter. Ho proprietà di sola scrittura. ci sono un modo per recuperare un PropertyDescriptorCollection compresi quelli?

/ Asger

È stato utile?

Soluzione

proprietà di sola scrittura sono una bestia rara, e non esistono nello spazio System.ComponentModel / PropertyDescriptor. PropertyDescriptors sono progettati per essere leggibili. Probabilmente potrei incidere HyperDescriptor a spessorare proprietà di sola scrittura, ma sarebbe un hack -. e sarebbe presumibilmente dovuto gettare eccezioni per get, che potrebbero avere un impatto chiamando il codice un po '

Per inciso; Io generalmente consiglio contro scrivere proprietà di sola; l'esempio da manuale che le persone tirano fuori è password (public string Password {private get;set;}) - I Preferiamo avere un metodo void SetPassword(string newPassword) ...

Che cosa è che si vuole realmente fare? Ci sono una serie di opzioni, tutte molto realizzabile:

  • uso solo di riflessione (lento, forse non è un'opzione)
  • uso Delegate.CreateDelegate (molto facile)
  • uso Expression.Compile ( piccolo più difficile, ma non di molto)
  • uso Reflection.Emit (abbastanza difficile)
  • shim proprietà di sola scrittura in PropertyDescriptor (abbastanza difficile)

Se me lo faccia sapere che cosa si vuole realmente fare (piuttosto che il modo in cui si sta attualmente tentando di farlo), potrei essere in grado di aiutare di più.

Per fare un esempio utilizzando Delegate.CreateDelegate (nota si vuole riporre il delegato da qualche parte e ri-usa un sacco di volte):

a cura di mostrare come si fa se non si conoscono i tipi specifici in fase di esecuzione

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

In alternativa utilizzando 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();
    }
}

Altri suggerimenti

System.Type.GetProperties() , invece, che restituisce tutte le proprietà. Si noti che questo restituisce un PropertyInfo[] invece di un PropertyDescriptorCollection

.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top