337 Star 2.6K Fork 788

GVP若汝棋茗/TouchSocket

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
dependencyproperty.mdx 6.30 KB
一键复制 编辑 原始数据 按行查看 历史
---
id: dependencyproperty
title: 依赖属性
---
### 定义
命名空间:TouchSocket.Core <br/>
程序集:[TouchSocket.Core.dll](https://www.nuget.org/packages/TouchSocket.Core)
## 一、说明
用过WPF的小伙伴一定对依赖属性不陌生。所以TouchSocket模仿其结构,创建了适用于网络框架的依赖属性。
## 二、什么是依赖属性?
我们知道常规属性,就是拥有get,set访问器的字段,叫做属性。
```csharp showLineNumbers
class MyClass
{
public int MyProperty { get; set; }
}
```
而依赖属性,则是具有注入特征的属性。它具有如下特性:
1. 可以像普通属性一样,声明在类内部(示例1),对外界的公布和常规数据一模一样。
2. 声明在静态类中,做成扩展方法,实现真正的注入型属性(示例2)。
3. 可以声明初始值。
### 2.1 内部声明
1. 继承**DependencyObject**
2. 按如下格式生成属性项(propdp代码块可快速实现)
```csharp showLineNumbers
class MyDependencyObject: DependencyObject
{
/// <summary>
/// 属性项
/// </summary>
public int MyProperty1
{
get { return GetValue(MyPropertyProperty1); }
set { SetValue(MyPropertyProperty1, value); }
}
/// <summary>
/// 依赖项
/// </summary>
public static readonly DependencyProperty<int> MyPropertyProperty1 =
DependencyProperty<int>.Register("MyProperty1", typeof(MyDependencyObject), 10);
}
```
### 2.2 扩展声明
扩展声明,必须要提前声明扩展类。
下列示例声明一个MyProperty的属性扩展。
```csharp showLineNumbers
public static class DependencyExtensions
{
/// <summary>
/// 依赖项
/// </summary>
public static readonly DependencyProperty<int> MyPropertyProperty2 =
DependencyProperty<int>.Register("MyProperty2", typeof(DependencyExtensions), 10);
/// <summary>
/// 设置MyProperty2
/// </summary>
/// <typeparam name="TClient"></typeparam>
/// <param name="client"></param>
/// <param name="value"></param>
/// <returns></returns>
public static TClient SetMyProperty2<TClient>(this TClient client, int value) where TClient : IDependencyObject
{
client.SetValue(MyPropertyProperty2, value);
return client;
}
/// <summary>
/// 获取MyProperty2
/// </summary>
/// <typeparam name="TClient"></typeparam>
/// <param name="client"></param>
/// <returns></returns>
public static int GetMyProperty2<TClient>(this TClient client) where TClient : IDependencyObject
{
return client.GetValue(MyPropertyProperty2);
}
}
```
那么这时候,**MyDependencyObject**对象即可赋值和获取**MyProperty2**的属性。
```csharp {2-3}
MyDependencyObject obj=new MyDependencyObject();
obj.SetMyProperty2(2);//扩展属性必须通过扩展方法
int value=obj.GetMyProperty2();
```
:::tip 提示
扩展的**SetMyProperty2**和**GetMyProperty2**不是必须的。如果没有这两个方法,我们依然可以使用**GetValue**和**SetValue**方法访问。
```csharp {2-3}
MyDependencyObject obj=new MyDependencyObject();
obj.SetValue(DependencyExtensions.MyPropertyProperty2,2);
int value=obj.GetValue(DependencyExtensions.MyPropertyProperty2);
```
:::
## 三、场景
假设以下情况:
有一个Person类,已经被封装好了,甚至已经被编译成dll了。但是他只有一个Age属性,如果我们想在开发后期再添加属性,应该怎么办呢?
常规做法就是继承,然后在子类添加属性。亦或者修改源码,重新编译。
无论哪一种都有很大的麻烦事。
继承,会让显式的Person类无法使用声明到子类的属性,到时候必须进行强制转换,而一旦继承分支多起来的话,将非常糟糕。
而重新编译,带来的问题就更大了,总不能把属性都声明在父类吧。何况还有dll版本依赖问题,同事推脱问题,巴拉巴拉。
```csharp showLineNumbers
public class Person
{
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }//常规属性
}
```
那我们如何解决呢?
我们可以在一开始,就将Person类按如下声明。继承DependencyObject。
```csharp showLineNumbers
public class Person : DependencyObject
{
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }//常规属性
}
```
:::tip 提示
如果不方便继承,也可以实现**IDependencyObject**接口,但是可能你需要复制**DependencyObject**的实现源码到你的基类中。
:::
然后,就Ok了。当后续你需要什么属性的时候,自己声明扩展即可。
这样,你就可以随意的往**Person**类中添加属性了。
```csharp showLineNumbers
public static class DependencyExtensions
{
/// <summary>
/// 依赖项
/// </summary>
public static readonly DependencyProperty<int> MyPropertyProperty2 =
DependencyProperty<int>.Register("MyProperty2", typeof(DependencyExtensions), 10);
/// <summary>
/// 设置MyProperty2
/// </summary>
/// <typeparam name="TClient"></typeparam>
/// <param name="client"></param>
/// <param name="value"></param>
/// <returns></returns>
public static TClient SetMyProperty2<TClient>(this TClient client, int value) where TClient : IDependencyObject
{
client.SetValue(MyPropertyProperty2, value);
return client;
}
/// <summary>
/// 获取MyProperty2
/// </summary>
/// <typeparam name="TClient"></typeparam>
/// <param name="client"></param>
/// <returns></returns>
public static int GetMyProperty2<TClient>(this TClient client) where TClient : IDependencyObject
{
return client.GetValue(MyPropertyProperty2);
}
}
```
:::tip 提示
在声明扩展时,还可以对**where TClient : IDependencyObject**进行泛型约束,这样,就能管理属性的作用域了。
:::
## 四、优缺点
**优点:**
1. 可以不声明在类内部。这意味着可以从外部注入。
2. 不需要初始赋值,也就意味着创建大量对象时,可以不需要占用太多内存。
**缺点:**
1. 对性能有一定性能影响。准确说,对于值类型,有拆装箱、查字典两个损耗。对于引用类型,会多一个字典查询操作。但是这种性能损耗,经实测,在1亿次存取时,才有不到一秒的差距。
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C#
1
https://gitee.com/RRQM_Home/TouchSocket.git
git@gitee.com:RRQM_Home/TouchSocket.git
RRQM_Home
TouchSocket
TouchSocket
master

搜索帮助