C#中的CLR属性、依赖属性与附加属性

  • CLR属性的主要特征

  1. 封装性

    • 隐藏字段的实现细节

    • 提供对字段的受控访问

  2. 访问控制

    • 可单独设置get/set访问器的可见性

    • 可创建只读或只写属性

  3. 计算属性

    • 可以在getter中执行计算逻辑

    • 不需要直接对应一个字段

  4. 验证逻辑

    • 可以在setter中添加值验证

    • 可以抛出异常拒绝无效值

  5. 通知机制

    • 可以手动实现属性变更通知(如INotifyPropertyChanged)

  6. 线程安全

    • 可以添加线程同步逻辑

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(中间语言)层面,属性是通过以下元数据表示的:

  1. Property表:记录属性名称、类型和访问器方法

  2. Method表:存储get/set方法实现

  3. Field表:对于自动属性,存储编译器生成的私有字段

属性访问性能

属性访问的性能与方法调用相当,因为:

  1. 简单属性(get;set;)通常会被JIT内联优化

  2. 复杂属性(包含逻辑的)与方法调用开销相同

  3. 虚属性(virtual)会有额外的虚方法调用开销

与依赖属性的比较

特性CLR属性依赖属性
存储直接存储在对象中存储在DependencyObject的全局字典中
绑定支持需实现INotifyPropertyChanged原生支持
动画支持不支持原生支持
默认值需在构造函数设置可通过元数据指定
继承不支持支持属性值继承
内存占用每个实例都有存储只有修改过的值才占用内存
适用场景普通业务对象WPF/Silverlight/UWP控件

CLR属性的高级用法

  1. 索引器

public string this[int index] { get { /*...*/ } set { /*...*/ } }
  1. 表达式体属性(C# 6+):

public string FullName => $"{FirstName} {LastName}";
  1. 初始化器(C# 6+):

public string Name { get; set; } = "Anonymous";
  1. 只读自动属性(C# 6+):

public string Id { get; } = Guid.NewGuid().ToString();

CLR属性是C#面向对象编程的基础设施,提供了字段访问的抽象层,既能保持简洁的语法,又能提供灵活的控制逻辑。

  • 依赖属性与附加属性

依赖属性(Dependency Property)

实现原理

依赖属性是WPF/Silverlight/UWP等XAML技术中的核心概念,它扩展了传统的CLR属性,提供了更丰富的功能:

  1. 属性值继承:子元素可以继承父元素的属性值

  2. 数据绑定支持:可以直接作为数据绑定的目标

  3. 动画支持:可以被动画系统直接操作

  4. 样式支持:可以通过样式设置

  5. 元数据支持:可以指定默认值、验证回调等

  6. 值优先级系统:多个值源按照优先级决定最终值

实现依赖属性的关键是通过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); }}
}

应用场景

  1. 自定义控件开发:为自定义控件添加可绑定、可样式化的属性

  2. 数据绑定:作为数据绑定的目标属性

  3. 动画:创建可动画化的属性

  4. 模板绑定:在控件模板中使用TemplateBinding

  5. 样式设置:通过样式设置多个控件的属性值

附加属性(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());}}}
}

应用场景

  1. 布局系统:如Grid.Row、Grid.Column等

  2. 服务模式:如ToolTipService.ToolTip、ScrollViewer.IsScrollable等

  3. 行为扩展:为现有控件添加额外功能

  4. 自定义布局面板:创建自己的布局容器时定义布局属性

两者比较

特性依赖属性附加属性
定义方式在定义类中使用在任何类中定义,可附加到其他对象
注册方法RegisterRegisterAttached
访问器实例属性静态方法
典型用途为类定义标准属性为其他类扩展属性

高级主题

  1. 属性值优先级:本地值 > 动画 > 本地样式 > 触发器 > 隐式样式 > 样式触发器 > 模板触发器 > 样式Setter > 默认值

  2. 属性变更回调:通过PropertyMetadata指定属性变化时的处理逻辑

  3. 验证回调:通过ValidateValueCallback进行值验证

  4. 强制回调:通过CoerceValueCallback强制属性值在特定范围内

依赖属性和附加属性是WPF等XAML技术的核心机制,理解它们的原理和用法对于开发复杂的XAML应用程序至关重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/84589.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【mysql】联合索引和单列索引的区别

区别核心&#xff1a;联合索引可加速多个字段组合查询&#xff0c;单列索引只能加速一个字段。 &#x1f539;联合索引&#xff08;复合索引&#xff09; INDEX(col1, col2, col3)适用范围&#xff1a; WHERE col1 ... ✅ WHERE col1 ... AND col2 ... ✅ WHERE col1 ..…

如何用 HTML 展示计算机代码

原文&#xff1a;如何用 HTML 展示计算机代码 | w3cschool笔记 &#xff08;请勿将文章标记为付费&#xff01;&#xff01;&#xff01;&#xff01;&#xff09; 在编程学习和文档编写过程中&#xff0c;清晰地展示代码是一项关键技能。HTML 作为网页开发的基础语言&#x…

大模型笔记_模型微调

1. 大模型微调的概念 大模型微调&#xff08;Fine-tuning&#xff09;是指在预训练大语言模型&#xff08;如GPT、BERT、LLaMA等&#xff09;的基础上&#xff0c;针对特定任务或领域&#xff0c;使用小量的目标领域数据对模型进行进一步训练&#xff0c;使其更好地适配具体应…

React Native UI 框架与动画系统:打造专业移动应用界面

React Native UI 框架与动画系统&#xff1a;打造专业移动应用界面 关键要点 UI 框架加速开发&#xff1a;NativeBase、React Native Paper、UI Kitten 和 Tailwind-RN 提供预构建组件&#xff0c;帮助开发者快速创建美观、一致的界面。动画提升体验&#xff1a;React Native…

在QT中使用OpenGL

参考资料&#xff1a; 主页 - LearnOpenGL CN https://blog.csdn.net/qq_40120946/category_12566573.html 由于OpenGL的大多数实现都是由显卡厂商编写的&#xff0c;当产生一个bug时通常可以通过升级显卡驱动来解决。 OpenGL中的名词解释 OpenGL 上下文&#xff08;Conte…

Qt::QueuedConnection详解

在多线程编程中&#xff0c;线程间的通信是一个关键问题。Qt框架提供了强大的信号和槽机制来处理线程通信&#xff0c;其中Qt::QueuedConnection是一种非常有用的连接类型。本文将深入探讨Qt::QueuedConnection的原理、使用场景及注意事项。 一、基本概念 Qt::QueuedConnecti…

X86 OpenHarmony5.1.0系统移植与安装

近期在研究X86鸿蒙,通过一段时间的研究终于成功了,在X86机器上成功启动了openharmony系统了.下面做个总结和分享 1. 下载源码 获取OpenHarmony标准系统源码 repo init -u https://gitee.com/openharmony/manifest.git -b refs/tags/OpenHarmony-v5.1.0-Release --no-repo-ve…

如何诊断服务器硬盘故障?出现硬盘故障如何处理比较好?

当服务器硬盘出现故障时&#xff0c;及时诊断问题并采取正确的处理方法至关重要。硬盘故障可能导致数据丢失和系统不稳定&#xff0c;影响服务器的正常运行。以下是诊断服务器硬盘故障并处理的最佳实践&#xff1a; 诊断服务器硬盘故障的步骤 1. 监控警报 硬盘监控工具&#…

vue3提供的hook和通常的函数有什么区别

Vue 3 提供的 hook&#xff08;组合式函数&#xff09; 和普通函数在使用场景、功能和设计目的上有明显区别&#xff0c;它们是 Vue 3 组合式 API 的核心概念。下面从几个关键维度分析它们的差异&#xff1a; 1. 设计目的不同 Hook&#xff08;组合式函数&#xff09; 专为 Vu…

Spark提交流程

bin/spark-submit --class org.apache.spark.examples.SparkPi --master yarn ./examples/jars/spark-examples_2.12-3.3.1.jar 10 这一句命令实际上是 启动一个Java程序 java org.apache.spark.deploy.SparkSubmit 并将命令行参数解析到这个类的对应属性上 因为master给…

Microsoft Copilot Studio - 尝试一下Agent

1.简单介绍 Microsoft Copilot Studio以前的名字是Power Virtual Agent(简称PVA)。Power Virutal Agent是2019年出现的&#xff0c;是低代码平台Power Platform的一部分。当时Generative AI还没有出现&#xff0c;但是基于已有的Conversation AI技术&#xff0c;即Microsoft L…

【源码剖析】2-搭建kafka源码环境

在上篇文章kafka核心概念中&#xff0c;解释了kafka的核心概念&#xff0c;下面开始进行kafka源码编译。为什么学习源码需要进行源码编译呢&#xff0c;我认为主要有两点&#xff1a; 可以进行debug&#xff0c;跟踪代码执行逻辑可以对源码改动&#xff0c;强化学习学习效果 …

小红书视频图文提取:采集+CV的实战手记

项目说明&#xff1a;这波视频&#xff0c;值不值得采&#xff1f; 你有没有遇到过这样的场景&#xff1f;老板说&#xff1a;“我们得看看最近小红书上关于‘旅行’的视频都说了些什么。”团队做数据分析的&#xff0c;立马傻眼&#xff1a;官网打不开、接口抓不着、视频不能…

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中&#xff0c;高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司&#xff0c;近期做出了一个重大技术决策&#xff1a;弃用长期使用的 Nginx&#xff0c;转而采用其内部开发…

从编辑到安全设置: 如何满足专业文档PDF处理需求

随着数字化办公的发展&#xff0c;PDF 已成为跨平台文档交互的标准格式。无论是在日常办公、学术研究&#xff0c;还是项目协作中&#xff0c;对 PDF 文件进行高效编辑与管理的需求日益增长。功能全面、操作流畅且无额外负担的 PDF 编辑工具&#xff0c;它是一款在功能上可与 A…

Kafka消费者组位移重设指南

#作者&#xff1a;张桐瑞 文章目录 一、Kafka 与传统消息引擎的核心差异二、重设消费者组位移的核心原因三、重设位移的两大维度与七种策略四、重设位移的实现方式&#xff08;一&#xff09;Java API 方式&#xff08;二&#xff09;命令行脚本方式&#xff08;Kafka 0.11&am…

分类模型:逻辑回归

1、针对设计&#xff1a;二分类 Logistic 回归最初是为二分类问题设计的&#xff0c; Logistic 回归基于概率&#xff0c;通过 Sigmoid 函数转换输入特征的线性组合&#xff0c;将任意实数映射到 [0, 1] 区间内。 通过引入一个决策规则&#xff08;通常是概率的阈值&#xff…

CppCon 2015 学习:C++ WAT

这段代码展示了 C 中的一些有趣和令人困惑的特性&#xff0c;尤其是涉及数组访问和某些语法的巧妙之处。让我们逐个分析&#xff1a; 1. assert(map[“Hello world!”] e;) 这一行看起来很不寻常&#xff0c;因为 map 在这里被用作数组下标访问器&#xff0c;但是在前面没有…

vscode自定义主题语法及流程

vscode c/c 主题 DIY 启用自己的主题(最后步骤) 重启生效 文件–>首选项–>主题–>颜色主题: 也可以在插件里找到哈 手把手教你制作 在C:\Users\jlh.vscode\extensions下自己创建一个文件夹 里面有两个文件和一个文件夹 具体内容: package.json: {"name&…

前端传递日期范围(开始时间和结束时间),后端解析及查询

前端技术&#xff1a;Vue3 TypeScript Element Plus 后端技术&#xff1a;Java Spring Boot MyBatis 应用效果&#xff1a; 原来方案 1、前端日期控件使用 el-date-picker&#xff0c;日期显示格式和日期值返回格式都为&#xff1a;YYYY-MM-DD <el-form :model"…