写点什么

C#的未来:扩展属性及更多

  • 2015-05-03
  • 本文字数:1675 字

    阅读完需:约 5 分钟

C#未来系列文章中的下一条提议希望能够使用扩展属性。这一功能是大家期盼已久的特性,但通常来说被认为是不可行的,因为它会带来内存泄露。

实际上,实现扩展属性所需的基础功能在.NET 4.0 中就已经具备了。这里的秘密在于,你可以使用某个 ConditionalWeakTable 类以保存对象与扩展字段之间的映射。其实创建 ConditionalWeakTable 的目的正是为了提供这种动态类型语言的功能。

Sam Harwell 为我们演示了如何正确地使用这个类:

复制代码
private static readonly ConditionalWeakTable<t strongbox=""><fieldtype>> _extensionField_f;
public static FieldType get_f(T obj)
{
StrongBox<fieldtype> box;
if (!_extensionField_f.TryGetValue(obj, out box))
return default(FieldType);
return box.Value;
}
public static void set_f(T obj, FieldType value)
{
StrongBox<fieldtype> box = _extensionField_f.GetOrCreateValue(obj);
box.Value = value;
}</fieldtype></fieldtype></fieldtype></t>

扩展类

以上这种方式虽然能够实现最终的目的,但它的语法并不简洁。因此一种被称为“扩展类”的概念就能够派上用场了。可以通过以下语法定义一个扩展类:

public extension class MyClassExtensions : MyClass

在 MyClassExtensions 中定义的每个方法或属性都会自动成为 MyClass 中的扩展方法或属性。在 MyClassExtensions 中定义成员看起来与在 MyClass 中直接定义成员没有任何差别。这种方式让你能够避免使用旧的语法,即将某个方法定义为静态方法,并在参数中包含一个“this”关键字。

在扩展类中定义的字段和事件将通过上述的 ConditionalWeakTable 所实现。属性可以明确指定对应的字段或是自动实现,在后一种情况下,其内部实现依然依赖于 ConditionalWeakTable 的使用。

静态扩展

由于扩展类概念的存在,使得一种被称为“静态扩展方法”的使用方式也成为可能。它允许你为某个类添加一个静态方法,与你为对象添加成员方法的方式相同。

为了澄清这种用法,Erik Schierboom 这样写道:

比方说,它能够允许我扩展 xUnit 中的 Assert 类。

思考

虽然这种做法在动态类型语言中很常见,但这种能够为某个类任意添加状态的能力还是让某些开发者感到有些不安。HellBrick 总结了人们对于扩展字段的顾虑:

看上去对这种功能的尝试是很自然的事,但我担心这个特性可能会很容易遭到误用。如果你想要为某个类的实例附加一个额外的状态,我认为在大部分情况下,更好的方式是继承这个类,或是为它创建一个包装器。无论是哪种做法,你的意图都很明确。使用某种像魔法一样自动附加的弱字段引用,就不清楚它的生命周期,将这种方式作为类的设计方式或许是一种非常廉价的方案,并且具有一定吸引力。但同时,它可能会导致出现一些复杂的代码,增加日后维护的困难。

对上述说法的一种反对意见认为,如果没有扩展字段,那么也不可能通过扩展提供自动属性。Chrisaut 继续这个讨论:

即使扩展字段这条提议通不过,只要属性的 setter 仍然是允许使用的,就会有开发者尝试着提出自己的解决方案,而其中有半数都存在着一些微秒的错误。比方说,他们可能会创建一个 Dictonary<MyClass, string> 并保存在属性中。额……这样一来这个实例就永远不会被垃圾回收了,这将带来内存泄露。大多数开发者甚至不知道弱引用和 ConditionalWeakTable 的存在。

因此如果我们真的要阻止附加额外状态的行为(也就是不希望引入扩展字段),那么我感觉唯一的方法就是明确地表示只允许属性的 getter,不支持属性的 setter,或者在自动属性中只支持 getter。

这样一来大概就可以了。但我猜使用者会试图打破这一限制,我不确定只支持 getter 是否能够涵盖用户所需的所有场景。或者我们也可以说它已经涵盖了足够多的场景,而剩余的部分不值得实现。

扩展字段的另一个问题是对可回收对象的存储。如果你在 ConditionalWeakTable 中保存了一个可回收(disposable)对象,你需要找到一种方式,在父对象被垃圾回收时显式地回收该对象。ConditionalWeakTable 不会自动为你实现这一功能,而依赖于终结器又存在着风险。

查看英文原文: C# Futures: Extension Properties and More

2015-05-03 05:184468
用户头像

发布了 428 篇内容, 共 166.2 次阅读, 收获喜欢 35 次。

关注

评论

发布
暂无评论
发现更多内容

深入浅出边缘云 | 5. 运行时控制

俞凡

架构 边缘计算 网络 深入浅出边缘云

兆骑科创双创服务平台,创新创业高层次人才引进,投融资对接

兆骑科创凤阁

迄今为止见过最详细的零拷贝技术讲解

C++后台开发

后端开发 零拷贝 Linux服务器开发 C/C++后台开发 C/C++开发

阿里SpringCloudAlibaba实战小抄(第五版)GitHub独家首发开源

冉然学Java

GitHub 开源 springcloudAlibaba spring-boot

从 VLAN 到 IPVLAN: 聊聊虚拟网络设备及其在云原生中的应用

阿里巴巴云原生

Linux 阿里云 云原生 容器服务 IPVLAN

阿里内部高并发核心编程笔记:多线程、锁、JMM、JUC、设计模式

冉然学Java

JMM 设计模式 java; 多线程高并发

JOIN查询时,我为什么建议你将小表放在前面?(NLJ,SNL,BNL算法全面解析)

董哥的黑板报

MySQL 数据库 后端 服务端 db

一个可以提前结项的敏捷项目

Bruce Talk

敏捷 Agile 敏捷项目

兆骑科创创新创业大赛承办,线上直播路演,企业孵化

兆骑科创凤阁

STM32+果云GA6-GPRSGSM模块+MQTT+HTTP协议连接中移OneNet上传GPS数据定位

DS小龙哥

8月月更

1500字简述 Apache ZooKeeper 的基本原理

wljslmz

Apache zookeeper 分布式 8月月更

阿里架构师力推jvm架构解析文档,把JVM调优实战讲的明明白白

Java工程师

Java JVM GC

设备树

贾献华

8月月更

MySQL存储引擎

武师叔

8月月更

基于 OPLG 从 0 到 1 构建统一可观测平台实践

阿里巴巴云原生

阿里云 分布式 云原生 可观测 全链路

Spring(二、配置文件)

开源 bean Spring JPA 8月月更

开源一夏 | 自从我使用HiFlow场景连接器后,在也不用担心成为“落汤鸡”了

叶秋学长

开源 8月月更 Hiflow

C#的未来:扩展属性及更多_C#_Jonathan Allen_InfoQ精选文章