TypeDescriptor.GetProperties (thisType) для возврата свойств, которые доступны только для записи - PullRequest
1 голос
/ 21 апреля 2009

Я пытаюсь получить все свойства от типа, но использование TypeDescriptor.GetProperties (thisType) предоставит мне только свойства, которые имеют как установщик, так и получатель. У меня есть свойства только для записи. Есть ли способ получить PropertyDescriptorCollection, в том числе те?

/ Asger

Ответы [ 2 ]

9 голосов
/ 21 апреля 2009

Свойства только для записи - редкий зверь, и они не существуют в пространстве System.ComponentModel / PropertyDescriptor. PropertyDescriptor s предназначены для чтения. Я мог бы, вероятно, взломать HyperDescriptor, чтобы подобрать свойства, доступные только для записи, но это был бы хак - и, вероятно, пришлось бы генерировать исключения для get, что могло бы немного повлиять на вызов кода.

в сторону; Я вообще советую против свойств только для записи; пример из учебника, который используют люди, это пароли (public string Password {private get;set;}) - я бы предпочел метод void SetPassword(string newPassword) ...

Что вы на самом деле хотите сделать? Здесь есть целый ряд вариантов, все они достижимы:

  • использовать только отражение (медленно; возможно, не вариант)
  • использовать Delegate.CreateDelegate (очень легко)
  • использовать Expression.Compile ( немного сложнее, но не намного)
  • использовать Reflection.Emit (довольно сложно)
  • свойства только для записи в PropertyDescriptor (довольно сложно)

Если вы дадите мне знать, что вы действительно хотите сделать (а не то, как вы в настоящее время пытаетесь это сделать), я мог бы помочь вам больше.

В качестве примера использования Delegate.CreateDelegate (обратите внимание, что вы захотите где-то спрятать делегат и использовать его много раз):

отредактировано, чтобы показать, как это сделать, если вы не знаете конкретные типы во время выполнения

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

Или, альтернативно, с помощью 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();
    }
}
2 голосов
/ 21 апреля 2009

Вместо этого используйте System.Type.GetProperties(), который возвращает все свойства. Обратите внимание, что это возвращает PropertyInfo[] вместо PropertyDescriptorCollection.

...