1

タイプからすべてのプロパティを取得しようとしていますが、TypeDescriptor.GetProperties(thisType) を使用すると、セッターとゲッターの両方を持つプロパティのみが提供されます。私は書き込み専用のプロパティを持っています。それらを含む PropertyDescriptorCollection を取得する方法はありますか?

/アスガー

4

2 に答える 2

9

書き込み専用プロパティはまれな獣であり、System.ComponentModel / PropertyDescriptor スペースには存在しません。PropertyDescriptors は読みやすいように設計されています。おそらくHyperDescriptor、書き込み専用プロパティをシム化するためにハックすることもできますが、それはハックであり、おそらく の例外をスローする必要がありget、呼び出しコードにかなりの影響を与える可能性があります。

余談として; 私は通常、書き込み専用のプロパティを使用しないことをお勧めします。人々がよく使う教科書の例はパスワード ( public string Password {private get;set;})void SetPassword(string newPassword)です。

あなたが本当にやりたいことは何ですか?ここにはさまざまなオプションがあり、すべて非常に達成可能です。

  • リフレクションのみを使用します (遅い; オプションではない可能性があります)
  • 使用するDelegate.CreateDelegate(非常に簡単)
  • 使用するExpression.Compile少し難しいですが、それほどではありません)
  • 使うReflection.Emit(かなり難しい)
  • 書き込み専用プロパティを shim する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()代わりに、すべてのプロパティを返すを使用してください。PropertyInfo[]これはではなく を返すことに注意してくださいPropertyDescriptorCollection

于 2009-04-21T11:23:06.480 に答える