Chinaunix首页 | 论坛 | 博客
  • 博客访问: 49380
  • 博文数量: 21
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 190
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-24 15:25
文章分类

全部博文(21)

文章存档

2013年(21)

我的朋友

分类: C#/.net

2013-07-05 12:44:27

Topic: C# – PropertyInfo vs. Property Descriptor

标题: PropertyInfo Property Descriptor.

为了定义如何从Tabular类型的数据对象拿到数据,你需要某种访问方法,其中之一就是PropertyDescriptor,另外一种就是PropertyInfo, PropertyInfo更像是一种反射机制的方案。但是,如果你可以创建PropertyInfo,那么实际的数据可以和PropertyInfo无关。

To define some way to retrieve the data from some tabular kind of data, you may need to have certain type of access mechanism, one is the PropertyDescriptor, and the other is PropertyInfo, the PropertyInfo is more like a reflection based solution – however since it is possible that you can create PropertyInfo, the actual data can be totally irrelevant to the reflection’s PropertyInfo as you can get from Type.GetProperties().

我们会用一个例子, 在该例子中, 我们创建一个衍生的列,该列的数据由前面列的值决定,该列的值至少可以转化为double)

We will use an example that a derived column will be the sum of the previous columns (whose type is double or at least can be converted to double).

定义如下的Column accessor.

Define a the Column accessor is like this:

点击(此处)折叠或打开

  1. public class MyPropertyDescriptor : PropertyDescriptor
  2.         {
  3.             #region Fields
  4.             private Type _componentType;
  5.             private double _value;
  6.             private PropertyInfo[] _aggregateColumns;
  7.             #endregion Fields
  8.  
  9.             #region Properties
  10.  
  11.             public PropertyInfo[] AggregatedColumns
  12.             {
  13.                 get { return _aggregateColumns; }
  14.             }
  15.  
  16.             #endregion Properties
  17.  
  18.             #region Constructors
  19.             public MyPropertyDescriptor(string name, Attribute[] attributes, Type componentType, PropertyInfo[] aggregateColumns)
  20.                 : base(name, attributes)
  21.             {
  22.                 _componentType = componentType;
  23.                 _aggregateColumns = aggregateColumns;
  24.             }
  25.           
  26.             #endregion Constructors
  27.  
  28.             #region Implemenation of PropertyDescriptor
  29.  
  30.             public override bool CanResetValue(object component)
  31.             {
  32.                 return false;
  33.             }
  34.  
  35.             public override Type ComponentType
  36.             {
  37.                 get { return _componentType; }
  38.             }
  39.  
  40.             public override object GetValue(object component)
  41.             {
  42.  
  43.                 if (AggregatedColumns != null)
  44.                 {
  45.                     var total = Enumerable.Select<PropertyInfo, double>(AggregatedColumns,
  46.                                                             (Func<PropertyInfo, double>)
  47.                                                             ((p => (double) p.GetValue(component, null)))).Sum();
  48.  
  49.                     return total;
  50.                 }
  51.                 else
  52.                 {
  53.                     return default(double);
  54.                 }
  55.             }
  56.  
  57.             public override bool IsReadOnly
  58.             {
  59.                 get { return true; }
  60.             }
  61.  
  62.             public override Type PropertyType
  63.             {
  64.                 get { return typeof(double); }
  65.             }
  66.  
  67.             public override void ResetValue(object component)
  68.             {
  69.                 //var defaultValueAttribute = (DefaultValueAttribute) base.Attributes[typeof (DefaultValueAttribute)];
  70.                 //if (defaultValueAttribute != null)
  71.                 //{
  72.                 // _value = (double) defaultValueAttribute.Value;
  73.                 //}
  74.             }
  75.  
  76.             public override void SetValue(object component, object value)
  77.             {
  78.                 throw new InvalidOperationException("SetValue is not supported in component");
  79.             }
  80.  
  81.             public override bool ShouldSerializeValue(object component)
  82.             {
  83.                 return false;
  84.             }
  85.             #endregion Implemenation of PropertyDescriptor
  86.         }


我们将采取如下的方法包装该Tabular data’s的接口。


And then we will wrap it so that we can wire up to the Tabular data’s interface.我们必须设置aggregation 方法,aggregation方法实际上定义了衍生列和其他列的关系。

And then we have to set up the aggregation methods like the relative relationship of the derived column with the rest columns

点击(此处)折叠或打开

  1. internal class TotalAggregableObjectColumnSet : ObjectColumnSet
  2.     {
  3.         #region Contrsuctor
  4.         public TotalAggregableObjectColumnSet(Type t, bool autoGenerateColumns) : base(t, autoGenerateColumns)
  5.         {
  6.             this.AddColumn(
  7.                 new MyColumn(new MyPropertyDescriptor("Total", new Attribute[0], t,
  8.                                                       t.GetProperties()
  9.                                                        .Where(
  10.                                                            (Func<PropertyInfo, bool>)
  11.                                                            (p => p.PropertyType == typeof (double))).ToArray())));
  12.         }
  13.         #endregion Contructor
  14.     }

现在我们已经介绍了PropertyDescriptor’s方法,我们再看看PropertyInfo的方法。


Now, we have introduced the PropertyDescriptor’s way, let’s further try to see how can we do with the help from the PropertyInfo.

点击(此处)折叠或打开

  1. public class MyPropertyInfo : PropertyInfo
  2.     {
  3.         #region Fields
  4.  
  5.         private readonly string m_name;
  6.         private readonly PropertyAttributes m_attributes;
  7.         private readonly Type m_componentType;
  8.         private readonly PropertyInfo[] m_aggregateColumns;
  9.         private readonly Type m_propertyType;
  10.  
  11.         #endregion Feilds
  12.  
  13.         #region Properties
  14.         // Name and Attributes is from the PropertyInfo (the abstract class)
  15.  
  16.         public Type ComponentType
  17.         {
  18.             get { return m_componentType; }
  19.         }
  20.         public PropertyInfo[] AggregatedColumns
  21.         {
  22.             get { return m_aggregateColumns; }
  23.         }
  24.         #endregion Properties
  25.  
  26.         #region Constructor
  27.         public MyPropertyInfo(string name, PropertyAttributes attributes, Type componentType, Type propertyType, PropertyInfo[] aggregateColumns) :base()
  28.         {
  29.             m_name = name;
  30.             m_attributes = attributes;
  31.             m_propertyType = propertyType;
  32.             m_componentType = componentType;
  33.             m_aggregateColumns = aggregateColumns;
  34.  
  35.         }
  36.         #endregion Constructor
  37.  
  38.         public override PropertyAttributes Attributes
  39.         {
  40.             get { return m_attributes; }
  41.         }
  42.  
  43.         public override bool CanRead
  44.         {
  45.             get { return true; }
  46.         }
  47.  
  48.         public override bool CanWrite
  49.         {
  50.             get { return false; }
  51.         }
  52.  
  53.         public override MethodInfo[] GetAccessors(bool nonPublic)
  54.         {
  55.             return null;
  56.         }
  57.  
  58.         public override MethodInfo GetGetMethod(bool nonPublic)
  59.         {
  60.             //throw new NotImplementedException();
  61.             return null;
  62.         }
  63.  
  64.         public override ParameterInfo[] GetIndexParameters()
  65.         {
  66.             return null;
  67.         }
  68.  
  69.         public override MethodInfo GetSetMethod(bool nonPublic)
  70.         {
  71.             //throw new NotImplementedException();
  72.             return null;
  73.         }
  74.  
  75.         public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
  76.         {
  77.             if (AggregatedColumns != null)
  78.             {
  79.                 var col = Enumerable.Select(AggregatedColumns, (p) =>
  80.                                                                    {
  81.                                                                        object value = p.GetValue(obj, null);
  82.                                                                        object convertedType = null;
  83.                                                                        if (PropertyType.IsAssignableFrom(value.GetType()))
  84.                                                                        {
  85.                                                                            convertedType = Convert.ChangeType(value, PropertyType);
  86.                                                                        }
  87.                                                                        return convertedType;
  88.                                                                    }).Sum(p => ((double) p)
  89.                                                                               );
  90.                 return col;
  91.             }
  92.             return null;
  93.         }
  94.  
  95.         public override Type PropertyType
  96.         {
  97.             get { return m_propertyType; }
  98.         }
  99.  
  100.         public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
  101.         {
  102.             if (!CanWrite)
  103.                 throw new NotSupportedException("Readonly Property, write not supported!");
  104.         }
  105.  
  106.         public override Type DeclaringType
  107.         {
  108.             get { return ComponentType; }
  109.         }
  110.  
  111.         public override object[] GetCustomAttributes(Type attributeType, bool inherit)
  112.         {
  113.             return null;
  114.         }
  115.  
  116.         public override object[] GetCustomAttributes(bool inherit)
  117.         {
  118.             return null;
  119.         }
  120.  
  121.         public override bool IsDefined(Type attributeType, bool inherit)
  122.         {
  123.             return false;
  124.         }
  125.  
  126.         public override string Name
  127.         {
  128.             get { return m_name; }
  129.         }
  130.  
  131.         public override Type ReflectedType
  132.         {
  133.             get { return PropertyType; }
  134.         }
  135.     }

我们可以使用PropertyColumn属性。


We can leverage the system’s PropertyColumn……

点击(此处)折叠或打开

  1. public class PropertyColumn : ColumnBase
  2.   {
  3.     private readonly string m_name;
  4.     private readonly Type m_type;
  5.     private readonly PropertyInfo m_property;
  6.     private readonly object[] m_index;
  7.  
  8.     public override string Name
  9.     {
  10.       get
  11.       {
  12.         return this.m_name;
  13.       }
  14.     }
  15.  
  16.     public override Type Type
  17.     {
  18.       get
  19.       {
  20.         return this.m_type;
  21.       }
  22.     }
  23.  
  24.     public PropertyColumn(PropertyInfo property)
  25.     {
  26.       ArgUtils.CheckNotNull("property", (object) property);
  27.       this.m_name = property.Name;
  28.       this.m_type = property.PropertyType;
  29.       this.m_property = property;
  30.     }
  31.  
  32.     public PropertyColumn(Type containerType, object index)
  33.     {
  34.       ArgUtils.CheckNotNull("containerType", (object) containerType);
  35.       ArgUtils.CheckNotNull("index", index);
  36.       this.m_property = containerType.GetProperty("Item", new Type[1]
  37.       {
  38.         index.GetType()
  39.       });
  40.       this.m_index = new object[1]
  41.       {
  42.         index
  43.       };
  44.       this.m_name = index.ToString();
  45.       this.m_type = this.m_property.PropertyType;
  46.     }
  47.  
  48.     public override object GetValue(object row)
  49.     {
  50.       ArgUtils.CheckNotNull("row", row);
  51.       try
  52.       {
  53.         return this.m_property.GetValue(row, this.m_index);
  54.       }
  55.       catch (TargetInvocationException ex)
  56.       {
  57.         throw ex.InnerException;
  58.       }
  59.     }
  60.   }


和如何计算该衍生列。

And the way to define how the columns should be calculated is

点击(此处)折叠或打开

  1. internal class TotalAggregablePropertyInfoObjectColumnSet : ObjectColumnSet
  2.     {
  3.         #region Constructor
  4.         public TotalAggregablePropertyInfoObjectColumnSet(string name, PropertyAttributes attributes, Type componentType,
  5.                                                           Type propertyType, PropertyInfo[] aggregateColumns,
  6.                                                           bool autoGenerateColumns)
  7.             : base(componentType, autoGenerateColumns)
  8.         {
  9.             AddColumn(new PropertyColumn(new MyPropertyInfo(name, attributes, componentType, propertyType,
  10.  
  11.                 //componentType.GetProperties().Where(p => p.PropertyType == typeof(double)).ToArray()
  12.                 aggregateColumns
  13.                 )));
  14.         }
  15.         #endregion Constructor
  16.     }

剩下的就是组装这些Tabular Provider列集合。

The next things to do is to wire up the ColumnSet and the Tabular Provider ..

Tabular Provider

Inside the Tabular Provider.

点击(此处)折叠或打开

  1. ColumnSet = new TotalAggregablePropertyInfoObjectColumnSet("Total", PropertyAttributes.None, typeof(TModel), typeof(double),
  2.                 typeof(TModel).GetProperties().Where(p => p.PropertyType.IsAssignableFrom(typeof(double))).ToArray(), true
  3.                 );


References:

Custom TypeDescriptor Class

阅读(2030) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~