我遇到了如何分离属性值及其访问者的问题。我把一些电子乐器封装成了类。一些包装由制造商提供的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;
}
}
}
连接后,我可以使用propertygrid编辑属性。我想使用序列化不仅可以将设置保存/恢复到文件,还可以在设备离线时编辑设置。通过上面的实现,如果设备未连接,则会抛出异常。我可以添加私有字段作为中间人和if语句来检查连接状态。但我有很多属性,希望有更好的方法。
是否有一种简单的方法来构建对象的“抽象”版本?我基本上想要一个克隆,但用私有字段替换原始访问器逻辑。我知道我可以使用GetMembers,但从那里去哪里?
答案 0 :(得分:1)
如果那是我,我会分开两件事,特别是:我的数据表示(用于序列化和大多数操作),b:制造商代表。根据您的要求,您几乎被迫沿着这条路线前进。然后,我将添加一个ApplyTo(Instrument)
方法,该方法可能使用序列化在名称到名称的基础上应用值。我会为你节省很多痛苦,特别是如果你将你的属性缩写为:
public float SomeSetting {get;set;}
这将允许您在离线时使用自己的模型纯粹。欺骗制造商模型听起来不太可能,尤其是在与序列化混合时。
答案 1 :(得分:1)
你有几种可能性,所以你必须根据你认为最可行的具体情况来决定。
<强>独立强>: 正如在Marc Gravell的回答中,您可以将模型完全与制造商分开,并使用外部解析器通过执行特定调用来处理所需的事务。如果您无法想象在原始DLL之上使用抽象层,我只会使用这种方法。
<强>装饰强>: 由于您要向给定库添加行为(检查连接),首先想到的是使用decorator pattern。这基本上归结为你首先暗示的东西;包装整个DLL并在必要时实现额外的中间逻辑。由于您手动编写了装饰器,因此可以根据需要对API进行大量的API更改。
<强>代理强>:
根据您要实现的中间逻辑的多样性,您可以考虑使用proxy pattern。例如。当你想要做的就是公开原始属性,并为每个属性添加相同的额外行为。当制造商的Instrument
类实现接口时,您可以生成一个在运行时实现此接口的类,并将调用重定向到制造商的实际DLL。这并不容易,但有一些库可以帮助您做到这一点。 Castle DynamicProxy,或更低级RunSharp。只有当你能从中获益时才考虑走这条路。例如。当你应该包装一个大型图书馆,或者一个经常随时间变化的图书馆时。
当你所要做的就是包装20个属性时,我建议你选择装饰器方法。如果您有空闲时间,那么在运行时代码生成和尝试生成代理时可能会感兴趣。
我可以通过使用RunSharp为您创建an example of a run time generated proxy,只是为了让您了解它是否是您想尝试的内容。 CreateGenericInterfaceWrapper<T>()
函数wraps any interface with a 'less generic' interface,在需要时生成强制转换。