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:
-
public class MyPropertyDescriptor : PropertyDescriptor
-
{
-
#region Fields
-
private Type _componentType;
-
private double _value;
-
private PropertyInfo[] _aggregateColumns;
-
#endregion Fields
-
-
#region Properties
-
-
public PropertyInfo[] AggregatedColumns
-
{
-
get { return _aggregateColumns; }
-
}
-
-
#endregion Properties
-
-
#region Constructors
-
public MyPropertyDescriptor(string name, Attribute[] attributes, Type componentType, PropertyInfo[] aggregateColumns)
-
: base(name, attributes)
-
{
-
_componentType = componentType;
-
_aggregateColumns = aggregateColumns;
-
}
-
-
#endregion Constructors
-
-
#region Implemenation of PropertyDescriptor
-
-
public override bool CanResetValue(object component)
-
{
-
return false;
-
}
-
-
public override Type ComponentType
-
{
-
get { return _componentType; }
-
}
-
-
public override object GetValue(object component)
-
{
-
-
if (AggregatedColumns != null)
-
{
-
var total = Enumerable.Select<PropertyInfo, double>(AggregatedColumns,
-
(Func<PropertyInfo, double>)
-
((p => (double) p.GetValue(component, null)))).Sum();
-
-
return total;
-
}
-
else
-
{
-
return default(double);
-
}
-
}
-
-
public override bool IsReadOnly
-
{
-
get { return true; }
-
}
-
-
public override Type PropertyType
-
{
-
get { return typeof(double); }
-
}
-
-
public override void ResetValue(object component)
-
{
-
//var defaultValueAttribute = (DefaultValueAttribute) base.Attributes[typeof (DefaultValueAttribute)];
-
//if (defaultValueAttribute != null)
-
//{
-
// _value = (double) defaultValueAttribute.Value;
-
//}
-
}
-
-
public override void SetValue(object component, object value)
-
{
-
throw new InvalidOperationException("SetValue is not supported in component");
-
}
-
-
public override bool ShouldSerializeValue(object component)
-
{
-
return false;
-
}
-
#endregion Implemenation of PropertyDescriptor
-
}
我们将采取如下的方法包装该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
-
internal class TotalAggregableObjectColumnSet : ObjectColumnSet
-
{
-
#region Contrsuctor
-
public TotalAggregableObjectColumnSet(Type t, bool autoGenerateColumns) : base(t, autoGenerateColumns)
-
{
-
this.AddColumn(
-
new MyColumn(new MyPropertyDescriptor("Total", new Attribute[0], t,
-
t.GetProperties()
-
.Where(
-
(Func<PropertyInfo, bool>)
-
(p => p.PropertyType == typeof (double))).ToArray())));
-
}
-
#endregion Contructor
-
}
现在我们已经介绍了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.
-
public class MyPropertyInfo : PropertyInfo
-
{
-
#region Fields
-
-
private readonly string m_name;
-
private readonly PropertyAttributes m_attributes;
-
private readonly Type m_componentType;
-
private readonly PropertyInfo[] m_aggregateColumns;
-
private readonly Type m_propertyType;
-
-
#endregion Feilds
-
-
#region Properties
-
// Name and Attributes is from the PropertyInfo (the abstract class)
-
-
public Type ComponentType
-
{
-
get { return m_componentType; }
-
}
-
public PropertyInfo[] AggregatedColumns
-
{
-
get { return m_aggregateColumns; }
-
}
-
#endregion Properties
-
-
#region Constructor
-
public MyPropertyInfo(string name, PropertyAttributes attributes, Type componentType, Type propertyType, PropertyInfo[] aggregateColumns) :base()
-
{
-
m_name = name;
-
m_attributes = attributes;
-
m_propertyType = propertyType;
-
m_componentType = componentType;
-
m_aggregateColumns = aggregateColumns;
-
-
}
-
#endregion Constructor
-
-
public override PropertyAttributes Attributes
-
{
-
get { return m_attributes; }
-
}
-
-
public override bool CanRead
-
{
-
get { return true; }
-
}
-
-
public override bool CanWrite
-
{
-
get { return false; }
-
}
-
-
public override MethodInfo[] GetAccessors(bool nonPublic)
-
{
-
return null;
-
}
-
-
public override MethodInfo GetGetMethod(bool nonPublic)
-
{
-
//throw new NotImplementedException();
-
return null;
-
}
-
-
public override ParameterInfo[] GetIndexParameters()
-
{
-
return null;
-
}
-
-
public override MethodInfo GetSetMethod(bool nonPublic)
-
{
-
//throw new NotImplementedException();
-
return null;
-
}
-
-
public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
-
{
-
if (AggregatedColumns != null)
-
{
-
var col = Enumerable.Select(AggregatedColumns, (p) =>
-
{
-
object value = p.GetValue(obj, null);
-
object convertedType = null;
-
if (PropertyType.IsAssignableFrom(value.GetType()))
-
{
-
convertedType = Convert.ChangeType(value, PropertyType);
-
}
-
return convertedType;
-
}).Sum(p => ((double) p)
-
);
-
return col;
-
}
-
return null;
-
}
-
-
public override Type PropertyType
-
{
-
get { return m_propertyType; }
-
}
-
-
public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
-
{
-
if (!CanWrite)
-
throw new NotSupportedException("Readonly Property, write not supported!");
-
}
-
-
public override Type DeclaringType
-
{
-
get { return ComponentType; }
-
}
-
-
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
-
{
-
return null;
-
}
-
-
public override object[] GetCustomAttributes(bool inherit)
-
{
-
return null;
-
}
-
-
public override bool IsDefined(Type attributeType, bool inherit)
-
{
-
return false;
-
}
-
-
public override string Name
-
{
-
get { return m_name; }
-
}
-
-
public override Type ReflectedType
-
{
-
get { return PropertyType; }
-
}
-
}
我们可以使用PropertyColumn属性。
We can
leverage the system’s PropertyColumn……
-
public class PropertyColumn : ColumnBase
-
{
-
private readonly string m_name;
-
private readonly Type m_type;
-
private readonly PropertyInfo m_property;
-
private readonly object[] m_index;
-
-
public override string Name
-
{
-
get
-
{
-
return this.m_name;
-
}
-
}
-
-
public override Type Type
-
{
-
get
-
{
-
return this.m_type;
-
}
-
}
-
-
public PropertyColumn(PropertyInfo property)
-
{
-
ArgUtils.CheckNotNull("property", (object) property);
-
this.m_name = property.Name;
-
this.m_type = property.PropertyType;
-
this.m_property = property;
-
}
-
-
public PropertyColumn(Type containerType, object index)
-
{
-
ArgUtils.CheckNotNull("containerType", (object) containerType);
-
ArgUtils.CheckNotNull("index", index);
-
this.m_property = containerType.GetProperty("Item", new Type[1]
-
{
-
index.GetType()
-
});
-
this.m_index = new object[1]
-
{
-
index
-
};
-
this.m_name = index.ToString();
-
this.m_type = this.m_property.PropertyType;
-
}
-
-
public override object GetValue(object row)
-
{
-
ArgUtils.CheckNotNull("row", row);
-
try
-
{
-
return this.m_property.GetValue(row, this.m_index);
-
}
-
catch (TargetInvocationException ex)
-
{
-
throw ex.InnerException;
-
}
-
}
-
}
和如何计算该衍生列。
And the way
to define how the columns should be calculated is
-
internal class TotalAggregablePropertyInfoObjectColumnSet : ObjectColumnSet
-
{
-
#region Constructor
-
public TotalAggregablePropertyInfoObjectColumnSet(string name, PropertyAttributes attributes, Type componentType,
-
Type propertyType, PropertyInfo[] aggregateColumns,
-
bool autoGenerateColumns)
-
: base(componentType, autoGenerateColumns)
-
{
-
AddColumn(new PropertyColumn(new MyPropertyInfo(name, attributes, componentType, propertyType,
-
-
//componentType.GetProperties().Where(p => p.PropertyType == typeof(double)).ToArray()
-
aggregateColumns
-
)));
-
}
-
#endregion Constructor
-
}
剩下的就是组装这些Tabular Provider列集合。
The next
things to do is to wire up the ColumnSet and the Tabular Provider ..
在Tabular Provider内
Inside the
Tabular Provider.
-
ColumnSet = new TotalAggregablePropertyInfoObjectColumnSet("Total", PropertyAttributes.None, typeof(TModel), typeof(double),
-
typeof(TModel).GetProperties().Where(p => p.PropertyType.IsAssignableFrom(typeof(double))).ToArray(), true
-
);
References:
Custom TypeDescriptor Class
阅读(2030) | 评论(0) | 转发(0) |