其實,反射還有另一種功能

來源:互聯網
上載者:User

說到反射嘛,估計各位不陌生,儘管很多人不知道到底是什麼,當然也有人將其看作是“反編譯”,有點像吧,但不能說是反編譯,雖然有個“反”字,但沒有“編譯”。

所以,我給反射下了這樣一個概述,準確與否,也不清楚:

反射可以動態擷取程式集資訊,或程式集中的類型資訊,以方便動態調用。

動態調用的好處是節約資源,通常情況下,我們添加程式集引用會在項目的引用中加入,這意味著只要應用程式運行了,這些程式集就會被載入,不管你是否需要調用。對於調用較少的程式集,如果考慮在調用時才載入,調用完了就釋放,這樣會在一定程度上節約記憶體佔用,當然這不是最佳化代碼的唯一方法,其實代碼最佳化是沒有關聯規則的,綜合而靈活去運用各種技巧都可以最佳化代碼和提高效能。

 

反射重點在於“動態”二字上,我忽然想到了資料繫結,於是我想到一些東西,平時我們做UI與資料的綁定時,多數情況下是已知資料項目類型有哪些公用屬性,進而綁定到對象的某個公用屬性上。那麼試想一下,假如我們事先不知道來自資料來源的對象是什麼結構,也不清楚它有哪些公用屬性,這樣資料繫結起來是不是會有麻煩呢?

這顯然是有麻煩的,而且,常規的思路是很難解決的,那麼這時候我們是不是想到了反射呢?不管來自資料來源的是什麼樣的物件類型,我只要通過反射將它的所有公用屬性都找出來,然後再取出對應屬性的值,再動態產生UI介面。若能如此,是不是很爽呢?

 

我這個人有個缺點,就是一旦想到什麼鬼點子,就會迫不及待地試試,故二話不說,馬上扔掉手頭上的東西,開啟電腦,啟動VS,就試著Coding起來了,這一Code還真沒白費力氣,總算Code出我的預期效果。

以下是我的大致思路:

首先,編寫一個類,提供操作,可以將任意類型對象的列錶轉換成WPF中的UI元素,接著再把轉換出來的UI元素列表當作資料來源,賦給ListBox的ItemsSource屬性,完成綁定。

這樣做的好處就是,不管來自資料來源的對象列表中的類有幾個公用屬性,只要能把它反射出來就行了。

下面是該轉換類的代碼。

using System;using System.Collections;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Reflection;using System.Windows;using System.Windows.Controls;using System.Windows.Media;using System.ComponentModel.DataAnnotations;namespace MyApp{    public class ObjectsConvertToUIFrmws    {        public IList<FrameworkElement> BuildUIList(IList objs)        {            List<FrameworkElement> uiList = new List<FrameworkElement>();            foreach (var obj in objs)            {                FrameworkElement fe = BuildUICore(obj);                uiList.Add(fe);            }            return uiList;        }        private PropertyInfo[] GetPropertiesFromObj(object o)        {            return o.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);        }        private Panel BuildUICore(object obj)        {            if (obj == null) return null;            PropertyInfo[] pis = GetPropertiesFromObj(obj);            Grid gridRoot = new Grid();            // 有多少個屬性就加入多少行,每行顯示一個            gridRoot.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });            gridRoot.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });            for (int i = 0; i < pis.Length; i++)            {                gridRoot.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });            }            for (int n = 0; n < pis.Length;n++ )            {                var attrs = pis[n].GetCustomAttributes(typeof(DisplayAttribute)).ToArray();                // 擷取屬性的值                object vl = pis[n].GetValue(obj);                if (vl is Color)                {                    // 如果欄位表示顏色,則設定為容器的背景色                    Color bgColor = (Color)vl;                    gridRoot.Background = new SolidColorBrush(bgColor);                }                else                {                    TextBlock tbDisplayName = new TextBlock();                    if (attrs != null && attrs.Count() > 0)                    {                        DisplayAttribute dispattr = attrs[0] as DisplayAttribute;                        tbDisplayName.Text = dispattr.Name;                    }                    else                    {                        tbDisplayName.Text = "未知欄位";                    }                    gridRoot.Children.Add(tbDisplayName);                    Grid.SetRow(tbDisplayName, n);                    Grid.SetColumn(tbDisplayName, 0);                    TextBlock tbValue = new TextBlock();                    // 如果屬性類型為日期時間,則轉換字串格式                    if (vl is DateTime)                    {                        tbValue.Text = ((DateTime)vl).ToString("yyyy-MM-dd HH:mm:ss");                    }                    else if (vl is double)                    {                        // 如果是雙精確度類型,則要保留三位小數                        tbValue.Text = ((double)vl).ToString("N3");                    }                    else                    {                        tbValue.Text = vl.ToString();                    }                    gridRoot.Children.Add(tbValue);                    Grid.SetRow(tbValue, n);                    Grid.SetColumn(tbValue, 1);                }            }            return gridRoot;        }    }}

 

通常情況下,在UI上顯示的字串最好不是屬性的名字,因為使用者看起來不方便,也可能看不懂,所以,這裡要求一個規範,就是在定義資料實體類時,為每個屬性加一個DisplayAttribute特性,並將其Name屬性設定為要在UI上呈現的字串。在反射過程中,會取出該特性,並訪問其Name屬性的值,然後將這個字串賦給UI象。

比如,現在,我們可以隨便定義一個類來做測試。

    public class TestDataItem    {        [Display(Name = "名字:")]        public string Name { get; set; }        [Display(Name = "年齡:")]        public int Age { get; set; }        [Display(Name = "城市:")]        public string City { get; set; }        public Color BackGround { get; set; }    }

由於,在前面的轉換類中,只要碰到是Color結構類型的屬性,就不將其顯示在UI上,而是作為UI面板容器(Grid對象)的背景色,因此,這裡定義資料對象類的時候,就不用為類型為Color的屬性添加DisplayAttribute特性了。

你在測試的時候,不一定要TestDataItem類那樣定義,你可以任意定義實體類,然後通過前面寫的轉換類,將期轉換為UI對象。

        public MainWindow()        {            InitializeComponent();            List<TestDataItem> list = new List<TestDataItem>();            list.Add(new TestDataItem { Name = "abc", Age = 12, City = "大連", BackGround = Colors.Yellow });            list.Add(new TestDataItem { Name= "def", Age = 20, City="上海", BackGround = Colors.Pink });            list.Add(new TestDataItem { Name = "gao", Age = 60, City="珠海", BackGround = Colors.SkyBlue });            ObjectsConvertToUIFrmws cf = new ObjectsConvertToUIFrmws();            this.lbList.ItemsSource = cf.BuildUIList(list);        }

你看,不管定義的實體是什麼結構,都可以動態產生UI元素,如此是不是很方便呢?

上面的例子最後得到如所示的結果。

 

最後,我聲明一下,我沒有說非得用這種方法來綁定資料不可,我只是結合了反射的用途而已,不要盲目使用,但我相信肯定有用,你在使用時不妨考慮一下,哪些情況下可以使用這種思路。

 

好吧,不寫太長的F話了,到此為止吧,拜拜。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.