[英]How to update and return a record using an interface in F#
在 C# 中,我正在使用以下我想移入 F# 的函数:
public virtual void BringToTop(LayersEnum _TopMostLayer)
{
if (LayerName == _TopMostLayer)
{
ZIndex = 10;
Visibility = Visibility.Visible;
}
else
{
ZIndex = DefaultZIndex;
Visibility = Visibility.Hidden;
}
}
假设我有以下 F# 定义,这是如何在 F# 中实现的:
type DocumentRadioButtons = ChartLayer | WritingLayer | ImageLayer | TranscriptionLayer | PublisherLayer
module WritingLayer=
type Model =
{ Name: string
Visibility: bool
DefaultZIndex: int
ZIndex: int
}
interface ILayer with
member this.Name with get() = this.Name
member this.Visibility with get() = this.Visibility
member this.DefaultZIndex with get() = this.DefaultZIndex
member this.ZIndex with get() = this.ZIndex
type ProgressNoteWin = {
ConfirmState: ConfirmState option
Encounter: view_doctor_encounter
LastName: string
DocumentLayer: DocumentRadioButtons
WritingLayer: WritingLayer.Model
ImageLayer: ImageLayer.Model
ChartLayer: ChartLayer.Model
}
我非常失败的尝试是:
let BringToTop rb (layer:ILayer) =
if rb.ToString() = layer.Name then {layer with Visibility =true} else {layer with Visibility = false }
{ m with WritingLayer = BringToTop documentRadioButton m.WritingLayer},
错误:未定义记录标签“可见性”
感谢您的任何帮助。
#附录:
最后,我想在 WritingLayer.Model、ImageLayer.Model 和 ChartLayer.Model 的不同记录类型上实现接口,用作:
{m with WritingLayer = BringToTop rb m.WritingLayer;
ImageLayer = BringToTop rb m.ImageLayer;
ChartLayer = rb m.ChartLayer}
谢谢您的考虑。
此代码将无法按原样运行:
let BringToTop rb (layer:ILayer) =
if rb.ToString() = layer.Name then
{ layer with Visibility =true }
else
{ layer with Visibility = false }
这是因为 F# 不会隐式向下转换为实现接口的类型。
第一个可能的解决方案:
从传递ILayer
切换到直接传递Model
。 然后您的代码将起作用。
第二个可能的解决方案:
我假设既然你有一个接口,你想把它作为数据类型而不是模型类型本身传递。 如果是这种情况,那么我建议使用对象表达式来更新数据,如下所示:
let mkILayer visible (layer: ILayer) =
{ new ILayer with
member this.Name = layer.Name
member this.Visibility = visible
member this.DefaultZIndex = layer.DefaultZIndex
member this.ZIndex = layer.ZIndex }
let BringToTop rb (layer:ILayer) =
if rb.ToString() = layer.Name then
mkILayer true layer
else
mkILayer false layer
第三个可能的解决方案
如果你对downcasting 没问题,你可以像这样隐藏你的第一layer
定义:
let BringToTop rb (layer:ILayer) =
if rb.ToString() = layer.Name then
let layer = layer :?> Model
{ layer with Visibility =true }
else
let layer = layer :?> Model
{ layer with Visibility = false }
但通常每当涉及向下转换时,就会产生代码异味,因此我真的建议改为构建接口的新实例。
我永远无法以我想要的方式做到这一点——通过使用 ILayer 接口来更新和返回与之关联的记录类型。 我最感兴趣的是更好的方法来做到这一点。
我最终所做的只是定义了三个特定的函数,每个类型一个:
let BringToTopWritingLayer rb layer:WritingLayer.Model =
if rb.ToString() = (layer :>ILayer).Name
then
{layer with Visibility = true}
else
{layer with Visibility = false}
let BringToTopImageLayer rb layer:ImageLayer.Model =
if rb.ToString() = (layer :>ILayer).Name
then
{layer with Visibility = true}
else
{layer with Visibility = false}
let BringToTopChartLayer rb layer:ChartLayer.Model =
if rb.ToString() = (layer :>ILayer).Name
then
{layer with Visibility = true}
else
{layer with Visibility = false}
用法如下:
{ m with DocumentLayer = documentRadioButton;
WritingLayer = BringToTopWritingLayer documentRadioButton m.WritingLayer;
ImageLayer = BringToTopImageLayer documentRadioButton m.ImageLayer;
ChartLayer = BringToTopChartLayer documentRadioButton m.ChartLayer}
这看起来非常多余,但它似乎可以正确编译。
一个更好的答案将不胜感激。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.