C#通用类型转换器

C#通用类型转换器

引子

    在最近做的一个项目中,因为要在设计时和运行时都需要通过PropertyGrid对一些自定义类型的属性进行编辑,比如弹出窗体式编辑、下拉框式的编辑还有属性展开编辑等各种方式,查看了VS自己的一些控件的属性编辑,知道这就是我想要的。
    还有,就是自定义类型和字符串之间的转换(类似于int.Parse和int.TryParse这些方法),也是我经常要用到和实现的。


技术准备
   针对第一个问题,我们都知道,在设计时对属性编辑,VS会自动调用这些类型的TypeConverterAttribute和EditorAttribute等这些类型定义时候设置的类型转换器和类型编辑器。
   针对第二个问题,就相对简单了,就是实现一个自定义类型的TypeConverter。
   由于现在我需要编辑的类型都是自定义类型,并且还有一定的嵌套关系,所有要想实现相应的效果,就必须得实现我所有自定义类型的“类型转换器”和“类型编辑器”。“所有的”自定义类型,想起这个就知道工作量,海了。在起初我还耐心实现了几个自定义类型的TypeConverter,(相信针对特定类型实现转换器,大伙儿都有自己的两把刷子,不废话了)。但是,想起来还有很多自定义类型,我实在忍无可忍了。
   根据以往实现TypeConverter的经验,发现了这些“类型转换器”之间很多的共同之处。抓住这点,我决定实现一个“通用的类型转换器”,把大部分的工作都交由它处理,岂不乐哉。

开始
   在.Net或C++中,要实现“通用性”,大家第一个想起来的肯定就是泛型了,不错,实现这个无非是使用了下面的几项技术:泛型,反射。
   现把这个“通用类型转换器”公布出来,可能还有些纰漏之处,还请大家多指教。
///////////////////////////////////////////////////////////// /// Copyright (C) 2009 Keepsoft /// All rights reserved /// /// File: TypeConverterGeneral.cs /// Author: tianfj /// CreateDate: 2009-4-17 0:25:15 /// Description:实现类型属性分别编辑的通用类型转换器 /// ///////////////////////////////////////////////////////////// using System; using System.Collections; using System.Collections.Generic; using System.Text; using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Globalization; using System.Reflection; namespace SkinSharpBuilder { /// <summary> /// 实现类型属性分别编辑的通用类型转换器 /// 使用注意:使用的时候应该先从这个通用类型转换器中继承一个自己的类型转换器,泛型T应该是类型转换器的目标类型 /// </summary> /// <typeparam name="T"></typeparam> public class TypeConverterGeneral<T> : TypeConverter where T : new() { public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) { return ((sourceType == typeof(string)) || base.CanConvertFrom(context, sourceType)); } public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { //字符串类似:ClassName { A=a, B=b, C=c } string strValue = value as string; if (strValue == null) { return base.ConvertFrom(context, culture, value); } strValue = strValue.Trim(); if (strValue.Length == 0) { return null; } if (culture == null) { culture = CultureInfo.CurrentCulture; } //char sepChar = culture.TextInfo.ListSeparator[0]; char sepChar = '|'; Type type = typeof(T); //1、去掉“ClassName { ”和“ }”两部分 string withStart = type.Name + " { "; string withEnd = " }"; if (strValue.StartsWith(withStart) && strValue.EndsWith(withEnd)) { strValue = strValue.Substring(withStart.Length, strValue.Length - withStart.Length - withEnd.Length); } //2、分割属性值 string[] strArray = strValue.Split(new char[] { sepChar }); //3、做成属性集合表 Hashtable properties = new Hashtable(); for (int i = 0; i < strArray.Length; i++) { string str = strArray[i].Trim(); int index = str.IndexOf('='); if (index != -1) { string propName = str.Substring(0, index); string propValue = str.Substring(index + 1, str.Length - index - 1); PropertyInfo pi = type.GetProperty(propName); if (pi != null) { //该属性对应类型的类型转换器 TypeConverter converter = TypeDescriptor.GetConverter(pi.PropertyType); properties.Add(propName, converter.ConvertFromString(propValue)); } } } return this.CreateInstance(context, properties); } public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) { return ((destinationType == typeof(InstanceDescriptor)) || base.CanConvertTo(context, destinationType)); } public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType == null) { throw new ArgumentNullException("destinationType"); } if (value is T) { if (destinationType == typeof(string)) { if (culture == null) { culture = CultureInfo.CurrentCulture; } //string separator = culture.TextInfo.ListSeparator + " "; string separator = " | "; StringBuilder sb = new StringBuilder(); Type type = value.GetType(); sb.Append(type.Name + " { "); PropertyInfo[] pis = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); for (int i = 0; i < pis.Length; i++) { if (!pis[i].CanRead) continue; Type typeProp = pis[i].PropertyType; string nameProp = pis[i].Name; object valueProp = pis[i].GetValue(value, null); TypeConverter converter = TypeDescriptor.GetConverter(typeProp); sb.AppendFormat("{0}={1}" + separator, nameProp, converter.ConvertToString(context, valueProp)); } string strContent = sb.ToString(); if (strContent.EndsWith(separator)) strContent = strContent.Substring(0, strContent.Length - separator.Length); strContent += " }"; return strContent; } if (destinationType == typeof(InstanceDescriptor)) { ConstructorInfo constructor = typeof(T).GetConstructor(new Type[0]); if (constructor != null) { return new InstanceDescriptor(constructor, new object[0], false); } } } return base.ConvertTo(context, culture, value, destinationType); } public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues) { if (propertyValues == null) { throw new ArgumentNullException("propertyValues"); } Type type = typeof(T); ConstructorInfo ci = type.GetConstructor(new Type[0]); if (ci == null) return null; //调用默认的构造函数构造实例 object obj = ci.Invoke(new object[0]); //设置属性 PropertyInfo[] pis = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); object propValue = null; for (int i = 0; i < pis.Length; i++) { if (!pis[i].CanWrite) continue; propValue = propertyValues[pis[i].Name]; if (propValue != null) pis[i].SetValue(obj, propValue, null); } return obj; } public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) { return true;//返回更改此对象的值是否要求调用 CreateInstance 方法来创建新值。 } public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) { //属性依照在类型中声明的顺序显示 Type type = value.GetType(); PropertyInfo[] pis = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); string[] names = new string[pis.Length]; for (int i = 0; i < names.Length; i++) { names[i] = pis[i].Name; } return TypeDescriptor.GetProperties(typeof(T), attributes).Sort(names); } public override bool GetPropertiesSupported(ITypeDescriptorContext context) { return true; } } }

 

 

 

使用举例

1、对属性进行分组编辑:

一些自定义类型

internal class LinearBrushConverter : TypeConverterGeneral<LinearBrush> { } /// <summary> /// 简单的线性渐变画刷信息 /// </summary> [TypeConverter(typeof(LinearBrushConverter))] internal class LinearBrush { public LinearBrush() { this.StartColor = Color.Black; this.EndColor = Color.Black; this.LinearDirection = LinearGradientMode.Horizontal; } public LinearBrush(Color startColor, Color endColor, LinearGradientMode linearDirection) { this.StartColor = startColor; this.EndColor = endColor; this.LinearDirection = linearDirection; } private DataGridViewCellStyle mCellStyle; public DataGridViewCellStyle CellStyle { get { if (this.mCellStyle == null) this.mCellStyle = new DataGridViewCellStyle(); return this.mCellStyle; } set { this.mCellStyle = value; } } private Color mStartColor; /// <summary> /// 获取或设置线性渐变的起始颜色 /// </summary> public Color StartColor { get { return mStartColor; } set { mStartColor = value; } } private Rectangle mRect; public Rectangle Rect { get { return mRect; } set { mRect = value; } } private Color mEndColor; /// <summary> /// 获取或设置线性渐变的结束颜色 /// </summary> public Color EndColor { get { return mEndColor; } set { mEndColor = value; } } private LinearGradientMode mLinearDirection; /// <summary> /// 获取或设置线性渐变的方向 /// </summary> public LinearGradientMode LinearDirection { get { return mLinearDirection; } set { mLinearDirection = value; } } }

在自定义的控件中使用LinearBrush类型添加一个属性

internal partial class ControlSkinPreview : UserControl { private LinearBrush mBackgroundBrush; /// <summary> /// 获取或设置该子元素的背景刷 /// </summary> public LinearBrush BackgroundBrush { private LinearBrush mBackgroundBrush; /// <summary> /// 获取或设置该子元素的背景刷 /// </summary> public LinearBrush BackgroundBrush { get { if (this.mBackgroundBrush == null) this.mBackgroundBrush = new LinearBrush(); return this.mBackgroundBrush; } set { this.mBackgroundBrush = value; } } } }

在VS属性设计框中就可以看到效果了。

 

2、自定义类型和字符串之间的转换

class MyClassConverter : TypeConverterGeneral<MyClass> {} [TypeConverter(typeof(MyClassConverter))] class MyClass { public MyClass() { } private int mMyInt; public int MyInt { get { return mMyInt; } set { mMyInt = value; } } private string mMyString; public string MyString { get { return mMyString; } set { mMyString = value; } } } private void tbtnAddButton_Click(object sender, EventArgs e) { this.imnuAddButton_Click(null, null); MyClass m = new MyClass(); m.MyInt = 10; m.MyString = "tianfj"; TypeConverter converter = TypeDescriptor.GetConverter(typeof(MyClass)); string s= converter.ConvertToString(m); Console.WriteLine(s); MyClass mm = converter.ConvertFromString(s) as MyClass; Console.WriteLine(mm.ToString()); }

 

 

结束
以上就是“通用类型转换器”的代码,及其使用举例,希望能减轻一点大家的重复的工作量,有什么不当之处,还请指出,方便大家,共同提高。

 

你可能感兴趣的:(String,object,C#,null,Constructor,attributes)