1

我试图从一个类型中获取所有属性,但是使用 TypeDescriptor.GetProperties(thisType) 只会为我提供属性,它同时具有 setter 和 getter。我有只写属性。有没有办法检索包括这些在内的 PropertyDescriptorCollection?

/阿斯格

4

2 回答 2

9

只写属性是一种罕见的野兽,在 System.ComponentModel / PropertyDescriptor 空间中不存在。PropertyDescriptors 被设计成可读的。我可能会破解HyperDescriptorshim 只写属性,但这将是一个破解 - 并且它可能必须为 抛出异常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);
    }
}

或者使用ExpressionAPI (.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();
    }
}
于 2009-04-21T12:28:25.057 回答
2

改为使用System.Type.GetProperties()它返回所有属性。请注意,这将返回 aPropertyInfo[]而不是 a PropertyDescriptorCollection

于 2009-04-21T11:23:06.480 回答