11

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

根据埃里克·利珀特:

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

然而,为了使这些功能有用,它们必须能够使用对象存储某种新的状态。似乎这样做的唯一方法是使用字典并将对象的每个实例与附加状态相关联。

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

有谁知道是否有可能获得对不会随着对象的内部状态变化而变化的对象的一些可散列引用?显然有一些内部机制可以跟踪单个对象,而不管它们的内存位置如何,但我不确定这是否会暴露给用户代码。

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

感谢您的任何见解。

4

2 回答 2

16

您正在寻找ConditionalWeakTable 类

于 2012-05-18T14:55:18.537 回答
0

** 完整答案已编辑 ** 属性保存在字典中,该字典使用对对象的弱引用作为键,并使用字符串-对象对的字典来存储属性及其值。

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

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

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

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

该想法的工作示例,使用 Wea​​kReference、静态字典和 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<WeakReference, Dictionary<string, object>> store
        = new Dictionary<WeakReference, Dictionary<string, object>>();

    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<string, object>());
        }
        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);
        }
    }
}
于 2012-05-18T15:00:51.733 回答