设为“只读”从 API 包装器返回的对象?
我正在工作中为 REST API(这是一个具有静态方法的静态类)编写一个包装器,它应该返回一个类或一个结构,其中包含从 API 请求返回的所有已解析的 Json。我使用 System.Web.Script.Serialization 解析 Json,如下所示:
JavaScriptSerializer jss = new JavaScriptSerializer();
QueryResult re = jss.Deserialize<QueryResult>(json);
然后我想在 QueryResult 上设置两个附加参数:使用的原始请求 Url 和 API 返回的确切 Json。一个矛盾是我希望整个对象仅在从 API 包装器返回后才被读取。我的第一个想法是只让变量通过构造函数设置,但是以我的方式解析 Json 永远不会让我使用构造函数。我想过有两个非常相似的对象,即一个在用于解析的包装器之外看不到的私有类,然后是一个使用构造函数一次设置只读参数的公共类,但这非常多余的,我宁愿以任何其他方式来做。
他们有什么设计模式或技巧可以让我这样做吗?我希望他们尝试分配给其中一个属性是一个语法错误,而不仅仅是一个被忽略的分配。
I'm writing a wrapper for a REST API (which is a static class with static methods) at work and it should return a class or a struct holding all the parsed Json returned from the API request. I'm parsing the Json using System.Web.Script.Serialization
like so:
JavaScriptSerializer jss = new JavaScriptSerializer();
QueryResult re = jss.Deserialize<QueryResult>(json);
I then want to set two additional parameters on the QueryResult: the original Request Url used and the exact Json returned by the API. The one contradiction is that I want the entire object to be read only once it's returned from the API wrapper. My first thought is to only let the variables be set through a constructor, but parsing Json the way that I am never lets me use a constructor. I thought about having two objects that are very similar, i.e. a private class that can't be seen outside of the wrapper that is used for parsing and then a public class who uses a constructor to set the read only parameters once, but that's very redundant and I'd rather do it just about any other way.
Are their any design patterns or tips to let me do this? I want it to be a syntactical error for them to try and assign to one of the properties, not just an ignored assignment.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
更新:
这听起来像是构建器模式的合适用例。您有一个可变对象,您可以使用它来设置您想要构建的任何内容的状态;那么这个类型负责构造一个实际可用的不可变(“锁定”)类型的实例。
例如:
那么您的调用代码可能如下所示:
老实说,我不知道这是否适合您的场景,但是“可以‘更新的只读对象’的一种常见解决方案'” 问题是有一个不可变类型,它返回带有修改的副本(例如,很像
DateTime.Add
)。因此,您可以进行如下操作...
然后调用代码需要执行以下操作:
Update:
This sounds like an appropriate use case for the builder pattern. You have a mutable object that you can use just to set up the state of whatever you want to build; then this type is responsible for constructing an instance of an immutable ("locked down") type which is actually usable.
For example:
Then your calling code might look like this:
I honestly have no idea if this is an appropriate answer for your scenario, but one common solution to the "read-only object that can be 'updated'" problem is to have an immutable type that returns copies with modifications (much like
DateTime.Add
, for example).So you could have an operation like...
Then calling code would need to do something like:
不幸的是,您已经发现为什么序列化通常被认为与正确的 OO 设计正交:为了方便起见,它破坏了封装。
我认为具有 get{} only 属性的包装对象是最好的选择。是的,它是多余的,但它有效,而且非常简单。
另外,您可能需要考虑为什么需要此功能。您不必太关心服务的使用者如何处理数据。您有什么特别的原因吗?
You've unfortunately discovered why serialization has often been considered orthogonal to proper OO design: it breaks encapsulation for the sake of convenience.
I think a wrapper object with get{} only properties is your best bet. Yeah, it's redundant, but it works, and it's pretty simple.
Also, you might want to consider why you need this functionality at all. What consumers of your service do with the data shouldn't be of much concern to you. Is there a particular reason you had in mind?
我看不出有什么好方法可以让某人设置属性时出现编译时错误,同时仍允许序列化器工作,但是如果设置的属性已经具有值,则可能会抛出异常:
只需确保您的所有类型都可为空或具有永远不会设置的默认值(即超出了可能的属性值的实际设置)。
I don't see a good way of making it a compile-time error for someone to set a property while still allowing the serializer to work, but you could throw an exception if a property is set that already has a value:
Just make sure all your types are nullable or have default values that will never be set (i.e. are outside the realistic set of possible property values).
您可以添加一种机制来在对象序列化后锁定对象...
you could add a mechanism to lockdown the object after it has been serialized...
您能让
QueryResult
实现接口IQueryResult
吗?使接口仅指定属性获取,而不指定属性设置。
当然,它不能绝对保证只读。但它确实避免了重复的类。如果可以的话,将
QueryResult
设为internal
类,这样它们就无法像我上面那样进行强制转换。这样你可以操纵它,但他们不能。Can you make
QueryResult
implement an interfaceIQueryResult
?Make the interface specify only property gets, not sets.
Sure, it's not absolutely guaranteed read-only. But it does avoid a duplicate class. If you can, make
QueryResult
aninternal
class so they can't cast to it, like I did above. That way you can manipulate it, but they can't.