我有关于如何分离属性值和它们的访问器的问题。我有一些电子乐器封装在类中。有些包了一个由制造商提供的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,但从那里去哪里?
你有几种可能性,所以你必须根据你的具体情况来决定哪种似乎是最可行的。
单独:正如Marc Gravell的回答,您可以将您的模型与制造商的模型完全分离,并使用外部解析器,该解析器通过执行特定调用来处理所需的事务。如果您无法想象在原始dll之上使用抽象层,我只会使用这种方法。
装饰:由于希望向给定库添加行为(检查连接),因此首先想到的是使用decorator模式。这基本上可以归结为你一开始所暗示的;包装整个DLL并在必要时实现额外的中间逻辑。由于您是手动编写装饰器,因此您可以对API进行大量更改,以使其适合您的需求。
:根据您想要实现的中间逻辑的变化程度,您可以考虑使用代理模式。例如,当你想做的只是公开原始属性,并为每个属性添加相同的额外行为时。当制造商的Instrument
类实现接口时,您可以在运行时生成一个实现该接口的类,并将调用重定向到制造商的实际DLL。这并不容易,但是有一些库可以帮助您做到这一点。城堡动态代理,或者更低级的RunSharp。只有当你能从中获益时才考虑走这条路。例如,当你要包装一个大的库,或者一个经常变化的库时。
当您所要做的只是包装20个属性时,我建议您使用decorator方法。当您有空闲时间时,使用运行时代码生成和尝试生成代理可能仍然很有趣。
我可以给你一个使用RunSharp创建的运行时生成代理的例子,只是为了让你感觉它是否是你想尝试的东西。CreateGenericInterfaceWrapper<T>()
函数用"非泛型"接口包装任何接口,在需要的地方生成强制转换。
如果是我,我会把这两件事分开,特别是a:我的数据表示(用于序列化和大多数操作)和b:制造商表示。你基本上是被你的需求逼着走这条路的。然后,我将添加一个ApplyTo(Instrument)
方法,例如,它可能使用序列化在名称到名称的基础上应用这些值。我认为这将为您省去很多麻烦,特别是当您将属性缩写为:
public float SomeSetting {get;set;}
这将允许您在离线时使用您自己的模型纯。欺骗制造商模型听起来不太可能,特别是当与序列化混合使用时。