-
CLR屬性的主要特征
-
封裝性:
-
隱藏字段的實現細節
-
提供對字段的受控訪問
-
-
訪問控制:
-
可單獨設置get/set訪問器的可見性
-
可創建只讀或只寫屬性
-
-
計算屬性:
-
可以在getter中執行計算邏輯
-
不需要直接對應一個字段
-
-
驗證邏輯:
-
可以在setter中添加值驗證
-
可以拋出異常拒絕無效值
-
-
通知機制:
-
可以手動實現屬性變更通知(如INotifyPropertyChanged)
-
-
線程安全:
-
可以添加線程同步邏輯
-
CLR屬性的實現原理
基本實現
CLR屬性本質上是編譯器生成的"語法糖",編譯后會轉換為方法調用:
// 源代碼
public class Person
{private string _name;public string Name{get { return _name; }set { _name = value; }}
}// 編譯后相當于
public class Person
{private string _name;public string get_Name(){return this._name;}public void set_Name(string value){this._name = value;}
}
自動實現屬性
C# 3.0引入的自動屬性進一步簡化了語法:
public string Name { get; set; }
編譯器會自動生成一個隱藏的私有字段(通常以<Name>k__BackingField命名)和對應的get/set方法。
屬性元數據
在IL(中間語言)層面,屬性是通過以下元數據表示的:
-
Property表:記錄屬性名稱、類型和訪問器方法
-
Method表:存儲get/set方法實現
-
Field表:對于自動屬性,存儲編譯器生成的私有字段
屬性訪問性能
屬性訪問的性能與方法調用相當,因為:
-
簡單屬性(get;set;)通常會被JIT內聯優化
-
復雜屬性(包含邏輯的)與方法調用開銷相同
-
虛屬性(virtual)會有額外的虛方法調用開銷
與依賴屬性的比較
特性 | CLR屬性 | 依賴屬性 |
---|---|---|
存儲 | 直接存儲在對象中 | 存儲在DependencyObject的全局字典中 |
綁定支持 | 需實現INotifyPropertyChanged | 原生支持 |
動畫支持 | 不支持 | 原生支持 |
默認值 | 需在構造函數設置 | 可通過元數據指定 |
繼承 | 不支持 | 支持屬性值繼承 |
內存占用 | 每個實例都有存儲 | 只有修改過的值才占用內存 |
適用場景 | 普通業務對象 | WPF/Silverlight/UWP控件 |
CLR屬性的高級用法
-
索引器:
public string this[int index] { get { /*...*/ } set { /*...*/ } }
-
表達式體屬性(C# 6+):
public string FullName => $"{FirstName} {LastName}";
-
初始化器(C# 6+):
public string Name { get; set; } = "Anonymous";
-
只讀自動屬性(C# 6+):
public string Id { get; } = Guid.NewGuid().ToString();
CLR屬性是C#面向對象編程的基礎設施,提供了字段訪問的抽象層,既能保持簡潔的語法,又能提供靈活的控制邏輯。
- 依賴屬性與附加屬性
依賴屬性(Dependency Property)
實現原理
依賴屬性是WPF/Silverlight/UWP等XAML技術中的核心概念,它擴展了傳統的CLR屬性,提供了更豐富的功能:
-
屬性值繼承:子元素可以繼承父元素的屬性值
-
數據綁定支持:可以直接作為數據綁定的目標
-
動畫支持:可以被動畫系統直接操作
-
樣式支持:可以通過樣式設置
-
元數據支持:可以指定默認值、驗證回調等
-
值優先級系統:多個值源按照優先級決定最終值
實現依賴屬性的關鍵是通過DependencyProperty
類和DependencyObject
基類:
public class MyControl : DependencyObject
{// 注冊依賴屬性public static readonly DependencyProperty MyPropertyProperty = DependencyProperty.Register("MyProperty", // 屬性名稱typeof(string), // 屬性類型typeof(MyControl), // 擁有者類型new PropertyMetadata("默認值")); // 元數據// CLR包裝器public string MyProperty{get { return (string)GetValue(MyPropertyProperty); }set { SetValue(MyPropertyProperty, value); }}
}
應用場景
-
自定義控件開發:為自定義控件添加可綁定、可樣式化的屬性
-
數據綁定:作為數據綁定的目標屬性
-
動畫:創建可動畫化的屬性
-
模板綁定:在控件模板中使用TemplateBinding
-
樣式設置:通過樣式設置多個控件的屬性值
附加屬性(Attached Property)
實現原理
附加屬性是一種特殊的依賴屬性,它允許一個類為其他類定義屬性,常用于布局系統和服務模式:
public class GridHelper
{// 注冊附加屬性public static readonly DependencyProperty RowCountProperty =DependencyProperty.RegisterAttached("RowCount", // 屬性名稱typeof(int), // 屬性類型typeof(GridHelper), // 擁有者類型new PropertyMetadata(1, OnRowCountChanged)); // 元數據// Get訪問器(必須為public static)public static int GetRowCount(DependencyObject obj){return (int)obj.GetValue(RowCountProperty);}// Set訪問器(必須為public static)public static void SetRowCount(DependencyObject obj, int value){obj.SetValue(RowCountProperty, value);}// 屬性變更回調private static void OnRowCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){if (d is Grid grid){// 當RowCount變化時,調整Grid的行定義grid.RowDefinitions.Clear();for (int i = 0; i < (int)e.NewValue; i++){grid.RowDefinitions.Add(new RowDefinition());}}}
}
應用場景
-
布局系統:如Grid.Row、Grid.Column等
-
服務模式:如ToolTipService.ToolTip、ScrollViewer.IsScrollable等
-
行為擴展:為現有控件添加額外功能
-
自定義布局面板:創建自己的布局容器時定義布局屬性
兩者比較
特性 | 依賴屬性 | 附加屬性 |
---|---|---|
定義方式 | 在定義類中使用 | 在任何類中定義,可附加到其他對象 |
注冊方法 | Register | RegisterAttached |
訪問器 | 實例屬性 | 靜態方法 |
典型用途 | 為類定義標準屬性 | 為其他類擴展屬性 |
高級主題
-
屬性值優先級:本地值 > 動畫 > 本地樣式 > 觸發器 > 隱式樣式 > 樣式觸發器 > 模板觸發器 > 樣式Setter > 默認值
-
屬性變更回調:通過PropertyMetadata指定屬性變化時的處理邏輯
-
驗證回調:通過ValidateValueCallback進行值驗證
-
強制回調:通過CoerceValueCallback強制屬性值在特定范圍內
依賴屬性和附加屬性是WPF等XAML技術的核心機制,理解它們的原理和用法對于開發復雜的XAML應用程序至關重要。