Frage

Ich versuche, alle Eigenschaften von einem Typ zu erhalten, aber mit TypeDescriptor.GetProperties (thisType) wird mich nur mit Eigenschaften liefern, die sowohl Setter und Getter hat. Ich habe schreibgeschützte Eigenschaften. Gibt es eine Möglichkeit, eine PropertyDescriptorCollection einschließlich der?

abrufen

/ Asger

War es hilfreich?

Lösung

Write-only Eigenschaften sind ein seltenes Tier, und sind nicht in dem System.ComponentModel / PropertyDescriptor Raum. PropertyDescriptors sind so ausgelegt, lesbar zu sein. Ich könnte wahrscheinlich HyperDescriptor hacken write-only Eigenschaften Shim, aber es wäre ein Hack -. Und es wäre vermutlich Ausnahmen für get werfen müssen, was ziemlich viel Aufruf Code auswirken könnte

Als beiseite; Ich rate generell gegen schreibgeschützte Eigenschaften; das Lehrbuch Beispiel, dass Menschen Passwörter Trab (public string Password {private get;set;}) - ich viel lieber eine void SetPassword(string newPassword) Methode haben würde ...

Was ist es, dass Sie tatsächlich tun wollen? Es gibt eine Reihe von Möglichkeiten hier, die alle sehr erreichbar:

  • Verwendung Reflexion allein (langsam, vielleicht keine Option)
  • Verwendung Delegate.CreateDelegate (sehr leicht)
  • Verwendung Expression.Compile (a kleine härter, aber nicht viel)
  • Verwendung Reflection.Emit (ziemlich hart)
  • Shim Nur-Schreib-Eigenschaften in PropertyDescriptor (ziemlich hart)

Wenn Sie lassen Sie mich wissen, was Sie wirklich tun wollen (und nicht so, wie Sie derzeit versuchen, es zu tun), ich könnte in der Lage sein, mehr zu helfen.

Als ein Beispiel unter Verwendung von Delegate.CreateDelegate (beachten Sie die Delegaten irgendwo verstauen möchten und wieder verwendet es viele Male):

bearbeitet zu zeigen, wie es zu tun, wenn Sie die spezifischen Typen zur Laufzeit nicht wissen,

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

oder alternativ mit der Expression API (.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();
    }
}

Andere Tipps

Verwenden Sie System.Type.GetProperties() statt, das alle Eigenschaften zurückgibt. Beachten Sie, dass dies eine PropertyInfo[] anstelle eines PropertyDescriptorCollection zurück.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top