在扩展方法中保留状态

C#团队之前曾考虑过向C#添加扩展属性,事件等。

Per Eric Lippert:

http://blogs.msdn.com/b/ericlippert/archive/2009/10/05/why-no-extension-properties.aspx

然而,为了使这些特征有用,它们必须能够用对象存储一些新的状态。 看起来这样做的唯一方法是使用字典并将对象的每个实例与其他状态相关联。

如果可以通过创建我自己的字典(以及可能的get / set扩展方法)“手动”复制此function将是有用的。 但是,为了将对象的特定实例与某个状态相关联,您需要散列对该对象的实际引用 。 在另一种语言中,您可以通过散列其内存位置来实现此目的,但是在C#中不能保证保持不变,并且使用不安全的代码来完成此function远非理想。

有没有人知道是否有可能获得一些对象的可引用引用,该对象在对象的内部状态发生变化时不会改变? 显然有一些内部机制可以跟踪单个对象而不管它们的内存位置如何,但我不确定它是否暴露给用户代码。

注意:简单地散列对象本身根本不起作用,因为GetHashCode()依赖于对象的内部状态而不是它所在的对象

感谢您的任何见解。

您正在寻找ConditionalWeakTable类 。

**编辑的全部答案**属性保存在字典中,该字典使用对象的弱引用作为键,以及使用字符串 – 对象对的字典来存储属性及其值。

要设置,获取或删除对象的属性,该对象将在字典中的弱引用中进行搜索。

处理未使用的属性可能有两种方法:

  • 检查弱引用的IsAlive,如果为false则删除字典中的条目
  • 在“可扩展”对象中实现IDisposable,并调用一个扩展方法来删除正在处理的对象的属性。

我在示例代码中包含了一个可选的using块,以便您可以调试并查看Dispose如何调用RemoveProperties扩展方法。 这当然是可选的,当对象是GC时,将调用该方法。

使用WeakReference,静态字典和IDisposable的想法的工作样本。

 using System; using System.Collections.Generic; using System.Linq; namespace ConsoleApplication3 { class Program { static void Main(string[] args) { using (PropertyLessClass plc = new PropertyLessClass()) { plc.SetProperty("age", 25); plc.SetProperty("name", "John"); Console.WriteLine("Age: {0}", plc.GetProperty("age")); Console.WriteLine("Name: {0}", plc.GetProperty("name")); } Console.ReadLine(); } } } public class PropertyLessClass : IDisposable { public void Dispose() { this.DeleteProperties(); } } public static class PropertyStore { private static Dictionary> store = new Dictionary>(); public static void SetProperty(this object o, string property, object value) { var key = store.Keys.FirstOrDefault(wr => wr.IsAlive && wr.Target == o); if (key == null) { key = new WeakReference(o); store.Add(key, new Dictionary()); } store[key][property] = value; } public static object GetProperty(this object o, string property) { var key = store.Keys.FirstOrDefault(wr => wr.IsAlive && wr.Target == o); if (key == null) { return null; // or throw Exception } if (!store[key].ContainsKey(property)) return null; // or throw Exception return store[key][property]; } public static void DeleteProperties(this object o) { var key = store.Keys.FirstOrDefault(wr => wr.IsAlive && wr.Target == o); if (key != null) { store.Remove(key); } } }