C#通用類型轉換器

來源:互聯網
上載者:User

C#通用類型轉換器

引子

    在最近做的一個項目中,因為要在設計時和運行時都需要通過PropertyGrid對一些自訂類型的屬性進行編輯,比如彈出表單式編輯、下拉框式的編輯還有屬性展開編輯等各種方式,查看了VS自己的一些控制項的屬性編輯,知道這就是我想要的。
    還有,就是自訂類型和字串之間的轉換(類似於int.Parse和int.TryParse這些方法),也是我經常要用到和實現的。

技術準備
   針對第一個問題,我們都知道,在設計時對屬性編輯,VS會自動調用這些類型的TypeConverterAttribute和EditorAttribute等這些類型定義時候設定的類型轉換器和類型編輯器。
   針對第二個問題,就相對簡單了,就是實現一個自訂類型的TypeConverter。
   由於現在我需要編輯的類型都是自訂類型,並且還有一定的嵌套關係,所有要想實現相應的效果,就必須得實現我所有自訂類型的“類型轉換器”和“類型編輯器”。“所有的”自訂類型,想起這個就知道工作量,海了。在起初我還耐心實現了幾個自訂類型的TypeConverter,(相信針對特定類型實現轉換器,大伙兒都有自己的兩把刷子,不廢話了)。但是,想起來還有很多自訂類型,我實在忍無可忍了。
   根據以往實現TypeConverter的經驗,發現了這些“類型轉換器”之間很多的共同之處。抓住這點,我決定實現一個“通用的類型轉換器”,把大部分的工作都交由它處理,豈不樂哉。

開始
   在.Net或C++中,要實現“通用性”,大家第一個想起來的肯定就是泛型了,不錯,實現這個無非是使用了下面的幾項技術:泛型,反射。
   現把這個“通用類型轉換器”公布出來,可能還有些紕漏之處,還請大家多指教。
/////////////////////////////////////////////////////////////<br />///Copyright (C) 2009 Keepsoft<br />/// All rights reserved<br />///<br />/// File: TypeConverterGeneral.cs<br />/// Author: tianfj<br />/// CreateDate: 2009-4-17 0:25:15<br />/// Description:實作類別型屬性分別編輯的通用類型轉換器<br />///<br />/////////////////////////////////////////////////////////////<br />using System;<br />using System.Collections;<br />using System.Collections.Generic;<br />using System.Text;<br />using System.ComponentModel;<br />using System.ComponentModel.Design.Serialization;<br />using System.Globalization;<br />using System.Reflection;</p><p>namespace SkinSharpBuilder<br />{<br /> /// <summary><br /> /// 實作類別型屬性分別編輯的通用類型轉換器<br /> /// 使用注意:使用的時候應該先從這個通用類型轉換器中繼承一個自己的類型轉換器,泛型T應該是類型轉換器的目標類型<br /> /// </summary><br /> /// <typeparam name="T"></typeparam><br /> public class TypeConverterGeneral<T> : TypeConverter where T : new()<br /> {<br /> public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)<br /> {<br /> return ((sourceType == typeof(string)) || base.CanConvertFrom(context, sourceType));<br /> }</p><p> public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)<br /> {<br /> //字串類似:ClassName { A=a, B=b, C=c }<br /> string strValue = value as string;<br /> if (strValue == null)<br /> {<br /> return base.ConvertFrom(context, culture, value);<br /> }<br /> strValue = strValue.Trim();<br /> if (strValue.Length == 0)<br /> {<br /> return null;<br /> }<br /> if (culture == null)<br /> {<br /> culture = CultureInfo.CurrentCulture;<br /> }<br /> //char sepChar = culture.TextInfo.ListSeparator[0];<br /> char sepChar = '|';</p><p> Type type = typeof(T);<br /> //1、去掉“ClassName { ”和“ }”兩部分<br /> string withStart = type.Name + " { ";<br /> string withEnd = " }";<br /> if (strValue.StartsWith(withStart) && strValue.EndsWith(withEnd))<br /> {<br /> strValue = strValue.Substring(withStart.Length, strValue.Length - withStart.Length - withEnd.Length);<br /> }<br /> //2、分割屬性值<br /> string[] strArray = strValue.Split(new char[] { sepChar });<br /> //3、做成屬性集合表<br /> Hashtable properties = new Hashtable();<br /> for (int i = 0; i < strArray.Length; i++)<br /> {<br /> string str = strArray[i].Trim();<br /> int index = str.IndexOf('=');<br /> if (index != -1)<br /> {<br /> string propName = str.Substring(0, index);<br /> string propValue = str.Substring(index + 1, str.Length - index - 1);<br /> PropertyInfo pi = type.GetProperty(propName);<br /> if (pi != null)<br /> {<br /> //該屬性對應類型的類型轉換器<br /> TypeConverter converter = TypeDescriptor.GetConverter(pi.PropertyType);<br /> properties.Add(propName, converter.ConvertFromString(propValue));<br /> }<br /> }<br /> }<br /> return this.CreateInstance(context, properties);<br /> }<br /> public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)<br /> {<br /> return ((destinationType == typeof(InstanceDescriptor)) || base.CanConvertTo(context, destinationType));<br /> }<br /> public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)<br /> {<br /> if (destinationType == null)<br /> {<br /> throw new ArgumentNullException("destinationType");<br /> }<br /> if (value is T)<br /> {<br /> if (destinationType == typeof(string))<br /> {<br /> if (culture == null)<br /> {<br /> culture = CultureInfo.CurrentCulture;<br /> }<br /> //string separator = culture.TextInfo.ListSeparator + " ";<br /> string separator = " | ";<br /> StringBuilder sb = new StringBuilder();<br /> Type type = value.GetType();<br /> sb.Append(type.Name + " { ");<br /> PropertyInfo[] pis = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);<br /> for (int i = 0; i < pis.Length; i++)<br /> {<br /> if (!pis[i].CanRead) continue;</p><p> Type typeProp = pis[i].PropertyType;<br /> string nameProp = pis[i].Name;<br /> object valueProp = pis[i].GetValue(value, null);</p><p> TypeConverter converter = TypeDescriptor.GetConverter(typeProp);</p><p> sb.AppendFormat("{0}={1}" + separator, nameProp, converter.ConvertToString(context, valueProp));<br /> }<br /> string strContent = sb.ToString();<br /> if (strContent.EndsWith(separator))<br /> strContent = strContent.Substring(0, strContent.Length - separator.Length);<br /> strContent += " }";<br /> return strContent;<br /> }<br /> if (destinationType == typeof(InstanceDescriptor))<br /> {<br /> ConstructorInfo constructor = typeof(T).GetConstructor(new Type[0]);<br /> if (constructor != null)<br /> {<br /> return new InstanceDescriptor(constructor, new object[0], false);<br /> }<br /> }<br /> }<br /> return base.ConvertTo(context, culture, value, destinationType);<br /> }</p><p> public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)<br /> {<br /> if (propertyValues == null)<br /> {<br /> throw new ArgumentNullException("propertyValues");<br /> }<br /> Type type = typeof(T);<br /> ConstructorInfo ci = type.GetConstructor(new Type[0]);<br /> if (ci == null) return null;<br /> //調用預設的建構函式構造執行個體<br /> object obj = ci.Invoke(new object[0]);<br /> //設定屬性<br /> PropertyInfo[] pis = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);<br /> object propValue = null;<br /> for (int i = 0; i < pis.Length; i++)<br /> {<br /> if (!pis[i].CanWrite) continue;<br /> propValue = propertyValues[pis[i].Name];<br /> if (propValue != null)<br /> pis[i].SetValue(obj, propValue, null);<br /> }<br /> return obj;<br /> }</p><p> public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)<br /> {<br /> return true;//返回更改此對象的值是否要求調用 CreateInstance 方法來建立新值。<br /> }</p><p> public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)<br /> {<br /> //屬性依照在類型中聲明的順序顯示<br /> Type type = value.GetType();<br /> PropertyInfo[] pis = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);<br /> string[] names = new string[pis.Length];<br /> for (int i = 0; i < names.Length; i++)<br /> {<br /> names[i] = pis[i].Name;<br /> }<br /> return TypeDescriptor.GetProperties(typeof(T), attributes).Sort(names);<br /> }</p><p> public override bool GetPropertiesSupported(ITypeDescriptorContext context)<br /> {<br /> return true;<br /> }</p><p> }<br />}<br />

 

 

 

使用舉例

1、對屬性進行分組編輯:

一些自訂類型

internal class LinearBrushConverter : TypeConverterGeneral<LinearBrush><br /> { }</p><p> /// <summary><br /> /// 簡單的線性漸層畫刷資訊<br /> /// </summary><br /> [TypeConverter(typeof(LinearBrushConverter))]<br /> internal class LinearBrush<br /> {<br /> public LinearBrush()<br /> {<br /> this.StartColor = Color.Black;<br /> this.EndColor = Color.Black;<br /> this.LinearDirection = LinearGradientMode.Horizontal;<br /> }<br /> public LinearBrush(Color startColor, Color endColor, LinearGradientMode linearDirection)<br /> {<br /> this.StartColor = startColor;<br /> this.EndColor = endColor;<br /> this.LinearDirection = linearDirection;<br /> }<br /> private DataGridViewCellStyle mCellStyle;<br /> public DataGridViewCellStyle CellStyle<br /> {<br /> get<br /> {<br /> if (this.mCellStyle == null)<br /> this.mCellStyle = new DataGridViewCellStyle();<br /> return this.mCellStyle;<br /> }<br /> set<br /> {<br /> this.mCellStyle = value;<br /> }<br /> }<br /> private Color mStartColor;<br /> /// <summary><br /> /// 擷取或設定線性漸層的起始顏色<br /> /// </summary><br /> public Color StartColor<br /> {<br /> get { return mStartColor; }<br /> set { mStartColor = value; }<br /> }<br /> private Rectangle mRect;<br /> public Rectangle Rect<br /> {<br /> get { return mRect; }<br /> set { mRect = value; }<br /> }<br /> private Color mEndColor;<br /> /// <summary><br /> /// 擷取或設定線性漸層的結束顏色<br /> /// </summary><br /> public Color EndColor<br /> {<br /> get { return mEndColor; }<br /> set { mEndColor = value; }<br /> }<br /> private LinearGradientMode mLinearDirection;<br /> /// <summary><br /> /// 擷取或設定線性漸層的方向<br /> /// </summary><br /> public LinearGradientMode LinearDirection<br /> {<br /> get { return mLinearDirection; }<br /> set { mLinearDirection = value; }<br /> }</p><p> }

在自訂的控制項中使用LinearBrush類型添加一個屬性

internal partial class ControlSkinPreview : UserControl<br /> {<br />private LinearBrush mBackgroundBrush;<br /> /// <summary><br /> /// 擷取或設定該子項目的背景刷<br /> /// </summary><br /> public LinearBrush BackgroundBrush<br /> {<br /> private LinearBrush mBackgroundBrush;<br /> /// <summary><br /> /// 擷取或設定該子項目的背景刷<br /> /// </summary><br /> public LinearBrush BackgroundBrush<br /> {<br /> get<br /> {<br /> if (this.mBackgroundBrush == null)<br /> this.mBackgroundBrush = new LinearBrush();<br /> return this.mBackgroundBrush;<br /> }<br /> set<br /> {<br /> this.mBackgroundBrush = value;<br /> }<br /> }<br /> }<br />}

在VS屬性設計框中就可以看到效果了。

 

2、自訂類型和字串之間的轉換

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

 

 

結束
以上就是“通用類型轉換器”的代碼,及其使用舉例,希望能減輕一點大家的重複的工作量,有什麼不當之處,還請指出,方便大家,共同提高。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.