繁体   English   中英

如何使用 F# 中的接口更新和返回记录

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM