C# 对象编辑和序列化初始化
我在如何分离属性值及其访问器方面遇到问题。我有一些电子仪器封装成类。有些包装了制造商提供的 DLL 来处理通信。
一个简单的例子:
public class Instrument
{
private ManufacturerDLL.Instrument _instrument;
public Instrument()
{
_instrument = new ManufacturerDLL.Instrument;
}
public float SomeSetting
{
get
{
return _instrument.SomeSetting;
}
set
{
_instrument.SomeSetting = value;
}
}
}
连接后,我可以使用属性网格编辑属性。我想使用序列化不仅将设置保存/恢复到文件,而且还可以在设备离线时编辑设置。通过上述实现,如果设备未连接,则会抛出异常。我可以添加私有字段作为中间人和 if 语句来检查连接状态。但我有很多属性,希望有更好的方法。
有没有一种简单的方法来构造对象的“抽象”版本?我基本上想要一个克隆,但用私有字段替换原始的访问器逻辑。我知道我可以使用 GetMembers,但是从哪里开始呢?
I'm having issues on how to seperate property values and their accessors. I have some electronic instruments encapsulated into classes. Some wrap a DLL which was provided by the manufacturer to handle communications.
A simple example:
public class Instrument
{
private ManufacturerDLL.Instrument _instrument;
public Instrument()
{
_instrument = new ManufacturerDLL.Instrument;
}
public float SomeSetting
{
get
{
return _instrument.SomeSetting;
}
set
{
_instrument.SomeSetting = value;
}
}
}
Once connected, I can edit the properties with a propertygrid. I want to use serialization to not only save/restore the settings to a file, but also edit the settings with the device offline. With the implementation above, exceptions will throw if the device is not connected. I could add private fields as a middle man and if statements to check for connection status. But I have a lot of properties and hope there is a better way.
Is there an easy method to construct an 'abstract' version of an object? I basically want a clone but replace the original accessors logic with private fields. I know I can use GetMembers, but where to go from there?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您有多种可能性,因此您必须根据您的具体情况做出最可行的决定。
单独:
正如 Marc Gravell 的回答一样,您可以将您的模型与制造商的模型完全分开,并使用外部解析器通过执行特定调用来处理所需的事务。仅当您无法想象在原始 DLL 之上使用抽象层时,我才会使用此方法。
装饰器:
由于您想要向给定库添加行为(检查连接),因此首先想到的是使用 装饰器模式。这基本上可以归结为你一开始所暗示的内容;包装整个 DLL 并在必要时实现额外的中间逻辑。由于您手动编写装饰器,因此您可以对 API 进行大量更改以满足您的需求。
代理:
根据您想要实现的中间逻辑的变化程度,您可以考虑使用代理模式。例如,当您想要做的只是公开原始属性,并为每个属性添加相同的额外行为时。当制造商的
Instrument
类实现接口时,您可以生成一个在运行时实现该接口的类,并将调用重定向到制造商的实际 DLL。这并不容易,但是有一些库可以帮助您做到这一点。 Castle DynamicProxy,或更底层的RunSharp。只有当您能够从中获益时才考虑走这条路。例如,当您应该包装一个大库或一个随着时间的推移经常变化的库时。当您所要做的就是包装 20 个属性时,我建议您采用装饰器方法。当您有一些空闲时间时,享受运行时代码生成和尝试生成代理可能仍然很有趣。
我可以给你 使用 RunSharp 创建的运行时生成代理的示例,只是为了让您了解它是否是您想要尝试的东西。
CreateGenericInterfaceWrapper()
函数 用“不太通用”的接口包装任何接口,在需要时生成强制转换。You have several possibilities, so you'll have to decide based on your specific situation which seems most feasible.
Separate:
As in Marc Gravell's answer, you could separate your model entirely from the manufacturer's and use an external parser which handles desired transactions by doing specific calls. I would only use this approach if you can't imagine an abstraction layer to work with on top of the original DLLs.
Decorator:
Since you want to add behavior to a given library (check for connection), the first thing that comes to mind is using the decorator pattern. This basically comes down to what you were implying in the first place; wrapping the entire DLL and implement extra intermediate logic where necessary. Since you write the decorator manually, there are plenty of API changes you can do in order to suit it to your needs.
Proxy:
Based on how varied this intermediate logic you want to implement is, you could consider using a proxy pattern. E.g. when all you want to do is expose the original properties, and add the same extra behavior for every property. When the
Instrument
classes of the manufacturer implement interfaces, you could generate a class which implements this interface at run time, and redirects the calls to the actual DLL of the manufacturer. This isn't easy, but there are a few libraries which can help you do just that. Castle DynamicProxy, or more low-level RunSharp. Only consider walking this path when you can reap the benefits of it. E.g. when you are supposed to wrap a big library, or a library which changes often over time.When all you have to do is wrap 20 properties, I suggest you go for the decorator approach. When you have some spare time on your hands it might still be interesting to have some fun with run time code generation and attempting to generate a proxy.
I can give you an example of a run time generated proxy created by using RunSharp, just to give you a feel of whether it is something you would like to attempt. The
CreateGenericInterfaceWrapper<T>()
function wraps any interface with a 'less generic' interface, generating casts where needed.如果是我,我会分开两件事,特别是a:我的数据表示(用于序列化和大多数操作),b:制造商表示。你几乎是被你的要求逼着走这条路的。然后,我会添加一个
ApplyTo(Instrument)
方法,该方法可能使用序列化在名称到名称的基础上应用值。我认为这将为您省去很多麻烦,特别是如果您将属性缩写为:这将允许您在离线时纯粹使用自己的模型。欺骗制造商模型听起来不太可能,尤其是与序列化混合时。
If that was me, I would separate the 2 things, specifically a: my representation of the data (used for serialization and most manipulation), and b: the manufacturers representation. You are pretty much forced down this route by your requirements. I would then add, for example, an
ApplyTo(Instrument)
method that applied the values on a name-to-name basis perhaps using serialization. I thing this will save you a lot of pain, especially if you abbreviate your properties to:This will allow you to work purely with your own model while offline. Spoofing the manfacturers model sounds unlikely, especially when mixed with serialization.