动态创建附加 属性

Create attached property dynamically

尝试重构一个 tedious solution,我想到了 绝妙的 动态创建附加属性的想法,基本上:

void SomeMethod()
{
    ...
    var dp = DependencyProperty.RegisterAttached("SomeUniqueOrGeneratedName333", typeof(object), typeof(CurrentClass));
    ...
}

这不是 recommended 方式。

我正在使用这样的属性(令人惊讶的是,如果有人将附加属性用于其他东西)作为与对象数据(即绑定)相关的一些存储。这些稍后在相同方法的 lambda 中检索(不确定它是如何调用的,closure 我能想到的最接近的词),例如:

// create attached property an store binding to retrieve result later
var dp = DependencyProperty.RegisterAttached("LolBinding", typeof(object), typeof(CurrentClass));
BindingOperations.SetBinding(obj, dp, someBinding);
// another ap and binding, this time with event (will trigger when DataContext for obj is set)
BindingOperations.SetBinding(obj, DependencyProperty.RegisterAttached("LolAnotherBinding", typeof(object), typeof(CurrentClass), new PropertyMetadata(null, (d, e) =>
{
     var value = obj.GetValue(dp); // accessing ap 
     if (value != null) { ... } // do something
})), Property);

这行得通。我可以附加任意多的属性:

for(int i = 0; i < 10000; i++)
    DependencyProperty.RegisterAttached("SomeName" + i, typeof(object), typeof(MainWindow));

但它有问题,因为它不可能 retrieve dependency property (nor via reflection). My guess (feel free to discover) 这是因为它们 不是类型 .

的静态成员

这是我的问题:可以这样做吗?

我担心的是内存(即泄漏)和性能。如果确认没问题,我可能会开始大量使用这种技术。

可能听起来像是基于意见,但我怀疑是否能够单独正确测试它。


编辑,这里是创建和检索这样的 mcve 属性 :

// put this into window constructor
var dp = DependencyProperty.RegisterAttached("SomeName", typeof(object), typeof(MainWindow));
SetValue(dp, "test"); // even trying to set value
// trying to access it by name
var a = DependencyPropertyDescriptor.FromName("SomeName", typeof(MainWindow), typeof(MainWindow), true);
var b = GetAttachedProperty(this, "SomeName", typeof(MainWindow)); // method from linked question

ab都是null。我只能通过传递引用来访问 dp

P.S.: 尝试创建具有相同名称的依赖项 属性 将抛出。所以应该有办法访问它。

我明白你的意思了。是的,DependencyPropertyDescriptor.FromName 对您的情况没有帮助,因为您没有在目标类型上定义 GetValue 和 SetValue 方法。但是,有一种方法可以通过一些反思来按名称获取依赖项 属性。需要反思,因为这个有用的方法(DependencyProperty.FromName)出于某种奇怪的原因是内部的:

// put this into window constructor
var dp = DependencyProperty.RegisterAttached("SomeName", typeof(object), typeof(MainWindow));
SetValue(dp, "test"); // even trying to set value                      
// do this only once per application
var fromNameMethod = typeof(DependencyProperty).GetMethod("FromName", BindingFlags.Static | BindingFlags.NonPublic);
var fromName = (Func<string, Type, DependencyProperty>) fromNameMethod.CreateDelegate(typeof(Func<string, Type, DependencyProperty>));
// now it's fast to call this method via delegate, almost 0 reflection costs
var a = fromName("SomeName", typeof(MainWindow));
var value = GetValue(a); // "test"

至于能不能用。当然,这可能不是附加属性的预期用途,但我认为这没有问题。依赖 属性 值存储在对象本身中,而不是在某个静态位置,因此一旦对象本身被收集,它们就会被收集。当然,附加属性本身在您注册后不会被收集,但这应该不是问题,除非您注册太多。