问题
Trying to refactor one tedious solution, I've come to brilliant idea of creating attached properties dynamically, basically:
void SomeMethod()
{
...
var dp = DependencyProperty.RegisterAttached("SomeUniqueOrGeneratedName333", typeof(object), typeof(CurrentClass));
...
}
It is not the recommended way.
I am using such properties (big surprise, like if someone uses attached properties for something else) as storage for some related to object data (namely bindings). Those are retrieved later in lambda of same method (not sure how is it called, closure the closest word I can think of), e.g.:
// 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);
This works. I can attach as many properties as I like:
for(int i = 0; i < 10000; i++)
DependencyProperty.RegisterAttached("SomeName" + i, typeof(object), typeof(MainWindow));
But it has problem as it's not possible to retrieve dependency property (nor via reflection). My guess (feel free to discover) it's because those are not static members of the type.
Here is my question: is it OK to do so?
My concerns are memory (namely leakages) and performance. I may start using this technique a lot if it gets confirmed to be ok.
May sounds like opinion based, but I doubt to be able to properly test this alone.
Edit, here is mcve to create and retrieve such property :
// 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
Both a
and b
are null
. I am only able to access dp
by passing reference around.
P.S.: attempting to create dependency property with same name will throw. So there should be a way to access it.
回答1:
I see what you mean now. Yes, DependencyPropertyDescriptor.FromName
will not help in your case because you don't define GetValue and SetValue methods on target type. However there is a way to get your dependency property by name with a bit of reflection. Reflection is needed because this useful method (DependencyProperty.FromName
) is for some strange reason internal:
// 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"
As for is it OK to use it. Of course this might not be the intended usage of attached properties, but I see no problems with that. Dependency property values are stored in the object itself, not in some static location, so they will get collected once object itself is collected. Of course attached properties themselves will not be collected after you registered them, but that should not be a problem unless you register too many.
来源:https://stackoverflow.com/questions/42088734/create-attached-property-dynamically