如何创建自定义*只写*依赖属性?
我需要知道创建只写依赖属性的过程是什么。我可以看到 DependencyProperty 类没有用于只写属性的特殊“Register”方法,但我不知道 RegisterAttached 方法是否适用于我想要执行的操作。
此属性需要是依赖属性,而不是简单的 CLR 属性。在内部,我的类需要对此属性进行 PropertyChangedCallback 以保持稳定。
我知道可以创建只写依赖属性,因为它在以下位置中明确说明:
Pro C# 2008 和 .NET 3.5 平台,第 1061 页。
然而,这是我可以在同一页面上找到“依赖属性”和“只写”的唯一地方。这位作者显然认为没有必要向读者展示除基本读写依赖属性之外的任何内容的过程。当然,这本书可能是一堆废话——但这本书看起来相当标准,所以我认为作者是正确的。我认为互联网上信息的缺乏源于这样一个事实:通常没有人需要建造这样的房产。
我知道想要创建自己的只写依赖属性听起来很可疑。我向你保证这在我想要的地方是有意义的。我的类有一个属性,其值仅对设置它的对象有用。如果另一个对象稍后请求该属性的值,则在不知道设置器的原始上下文的情况下,它将无法从该值中获得任何理性意义。
该属性不用于提供信息。让外部对象尝试以这种方式使用属性值是有问题的、危险的和安全风险。所以我认为最好的设计是禁止对该属性的读取操作。任何使用我的类的人都会发现他们被迫按照预期的方式使用该类,这最终会变得更好、更干净。
I need to know what the procedure is for making a write-only dependency-property. I can see that the DependencyProperty class does not have a special "Register" method for write-only properties, but I have no idea whether the RegisterAttached method may apply to what I am trying to do.
This property needs to be a dependency-property, rather than a simple CLR property. Internally, my class requires a PropertyChangedCallback on this property in order to remain stable.
I know that write-only dependency-properties can be created, because it is stated quite clearly in:
Pro C# 2008 and the .NET 3.5 Platform, Page 1061.
However, this is the only place where I can even find "dependency property" and "write only" on the same page. And this author apparently did not think it was necessary to actually show the reader the procedure for anything other than a basic read-write dependency-property. Of course, this book could be a load of BS - but this book looks pretty standard, so I think it's a pretty safe bet that the author is correct. I assume the lack of information on the internet stems from the fact that nobody generally needs to make a property like this.
I know it sounds very questionable to want to make your own write-only dependency-property. I assure you it makes sense where I want it. My class has a property whose value is only useful to the object setting it. If another object were to request the value of this property later, it wouldn't be able to make any rational sense out of the value without knowing the original context of the setter.
This property is not intended to be used for informational purposes. Letting outside objects attempt to use the property value this way is problematic, dangerous, and a security risk. So I believe the best design is to prohibit read operations on this property. Anyone using my class will find that they are forced to use the class the way it was intended, which will work out much better and cleaner in the end.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你不能,这似乎是设计使然。虽然我可以理解您对上述书籍的处理方式,并且绝不质疑其质量,但我仍然认为这是某种复制粘贴或类似的问题。这是我的推理:
WPF 属性系统代码
WPF 属性系统设计
特别是后两点概述了设计约束,即依赖属性值始终可以通过 GetValue()/SetValue() ,无论它们的 CLR 包装器是访问受限还是完全可用,唯一的例外是专门考虑的 只读依赖属性。
因此,正如 Jeffs答案已经暗示,仅删除 getter 例如并不能真正阻止任何人通过 GetValue(),尽管这至少可能“减少自定义类立即暴露的命名空间”。任何此类语义解决方法的用处是使属性值的可见性/可访问性稍微降低,并且检索到的值对客户端来说本质上是无用的,如 Jeff 当然取决于您的特定场景。
You can't, this appears to be by design. While I can understand your approach to the mentioned book and am in no way questioning its quality, I'd still presume this to be some sort of copy&paste or similar issue. Here is my reasoning:
WPF property system code
WPF property system design
Especially the latter two points are outlining the design constraint, that dependency property values are always accessible via GetValue()/SetValue(), no matter whether their CLR wrappers are access restricted or available at all, with the only exception being the specifically accounted for Read-Only Dependency Properties.
Consequently, as Jeffs answer implies already, just removing the getter for example does not really prevent anyone accessing the property via GetValue(), though this may at least 'reduce the immediately exposed namespace of a custom class'. The usefulness of any such semantic workaround of making the property value somewhat less visible/accessible and the retrieved value inherently useless for clients as suggested by Jeff depends on your particular scenario of course.
有趣的是,这绝对是一种罕见的情况,我有兴趣了解更多它的功能。
您是否会考虑通过绑定或 GetValue 为读取提供无效值(例如 null),而只是没有 CLR getter?
使用私有 DependencyProperty 来存储您关心的“真实”值,或仅存储私有成员变量。
在属性更改回调中,始终将值恢复为原始值,同时存储设置的新值。
我现在大部分时间都花在 Silverlight 控件开发上,因此该属性适用于 WPF 和 Silverlight 领域,并且不使用强制转换或类似的任何有趣的东西。不过,也许它会让你走上正确的道路。
Interesting, this is definitely a rare scenario, I'd be interested to hear more in what it enables.
Would you consider the idea of providing an invalid value (such as null) for reads through binding or GetValue, while just not having a CLR getter?
Either use a private DependencyProperty to store the "real" value you care about, or just a private member variable.
In the property changed callback, always revert the value back to the original value, while storing away the new value that was set.
I spend most of my time doing Silverlight control development now, so this property works in WPF and Silverlight-land, and doesn't use coercian or anything fun like that. Maybe it gets you going on the right track, though.
看起来您可以通过依赖属性定义中应用的
FrameworkPropertyMetadata
使用与该属性关联的CoerceValueCallback
。只需安装一个回调,该回调接受第二个参数(新值),通过您自己的只写机制将其传递给对象,然后返回null
(或者对于值类型,default(T) )。
确实,“.NET 会记住强制转换之前的原始值”,但它不会通过数据绑定进行传播。调用
GetValue
将返回强制值,该值不会泄漏任何内容。我使用它来为我的主要属性(一个字节序列)的值实现单向便利设置器。例如,用户可以绑定字符串,以将主要属性设置为编码字节(ASCII 或 UTF-8,具体取决于设置的属性)。但并非所有字节序列都是有效的 UTF-8,因此不可能反转转换并通过便利属性读回字符串。
强制处理程序可以通过元数据替换来删除,因此这不能提供安全性,但可以防止开发人员意外地以错误的方式创建耦合。
It looks like you can use the
CoerceValueCallback
associated with the property via theFrameworkPropertyMetadata
applied in the dependency property definition. Just install a callback that takes the second argument, the new value, passes it to the object via your own write-only mechanism, then returnsnull
(or for value types,default(T)
).It's true that ".NET remembers the original value prior to coercion", but it won't be propagated via data-binding. Calls to
GetValue
will return the coerced value, which doesn't leak anything.I'm using this to implement one-way convenience setters for the value of my primary property, which is a sequence of bytes. A user can bind a string, for example, to set the primary property to the encoded bytes (ASCII or UTF-8, depending what property is set). But not all byte sequences are valid UTF-8, so it isn't possible to reverse the conversion and read a string back through the convenience property.
The coercion handler can be removed via metadata replacement, so this isn't providing security, but it will prevent developers from accidentally creating coupling in wrong ways.
我很困惑为什么你不能让“get”返回任何有用的东西?
但此外,也许您只是没有实现杰夫示例中的“OnMyWriteOnlyDependencyPropertyPropertyChanged”。
如果没有人能读到它,就没有真正的理由举办这个活动,对吗?
I'm confused as to why you can't just have the 'get' return nothing useful?
But furthermore, perhaps you just don't implement the 'OnMyWriteOnlyDependencyPropertyPropertyChanged', in Jeff's example.
No real reason to have the event, if no-one can read it, right?