typedescriptor.getProperties (Thistype) لإرجاع الخصائص، والتي هي الكتابة فقط
-
12-09-2019 - |
سؤال
أحاول الحصول على جميع الخصائص من نوع، ولكن باستخدام TypedEScriptor.getProperties (Thistype) ستزودني فقط بالخصائص، والتي تحتوي على Sedter و A Getter. لدي خصائص الكتابة فقط. هل هناك طريقة لاسترداد خصائص PropertyDescriptorCollection بما في ذلك تلك؟
/ asgher.
المحلول
خصائص الكتابة فقط هي وحش نادر، ولا توجد في مساحة System.componentModel / PropertyDescriptor. PropertyDescriptor
S مصممة لتكون مقروءة. ربما يمكن أن اختراق 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);
}
}
أو بدلا من ذلك باستخدام 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();
}
}
نصائح أخرى
يستخدم System.Type.GetProperties()
بدلا من ذلك، يؤدي ذلك إلى إرجاع جميع الخصائص. لاحظ أن هذا يعود PropertyInfo[]
بدل من PropertyDescriptorCollection
.