简体   繁体   English

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

[英]How to update and return a record using an interface in F#

In C#, I am using the following function which I want to move into F#:在 C# 中,我正在使用以下我想移入 F# 的函数:

public virtual void BringToTop(LayersEnum _TopMostLayer)
        {
            if (LayerName == _TopMostLayer)
            {
                ZIndex = 10;
                Visibility = Visibility.Visible;
            }
            else
            {
                ZIndex = DefaultZIndex;
                Visibility = Visibility.Hidden;
            }
        }

Assuming I have the following F# definitions, how is this implemented in F#:假设我有以下 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
      } 

My very FAILED attempt is:我非常失败的尝试是:

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},

Error: The record label "Visibility" is not defined错误:未定义记录标签“可见性”

Thank you for any help.感谢您的任何帮助。

#Addendum: #附录:

Ultimately, I would like to implement the interface on the different record types of WritingLayer.Model, ImageLayer.Model, and ChartLayer.Model to be used as:最后,我想在 WritingLayer.Model、ImageLayer.Model 和 ChartLayer.Model 的不同记录类型上实现接口,用作:

{m with WritingLayer = BringToTop rb m.WritingLayer; 
  ImageLayer = BringToTop rb m.ImageLayer; 
  ChartLayer = rb m.ChartLayer}

Thank you for your consideration.谢谢您的考虑。

This code won't work as-is:此代码将无法按原样运行:

let BringToTop rb (layer:ILayer) = 
    if rb.ToString() = layer.Name then
        { layer with Visibility =true }
    else
        { layer with Visibility = false }

This is because F# doesn't implicitly downcast to a type that implements the interface.这是因为 F# 不会隐式向下转换为实现接口的类型。

First potential solution:第一个可能的解决方案:

Switch from being passed an ILayer to just being passed a Model directly.从传递ILayer切换到直接传递Model Then your code will work.然后您的代码将起作用。

Second potential solution:第二个可能的解决方案:

I'm assuming that since you have an interface, you want to pass that around as the data type rather than the model type itself.我假设既然你有一个接口,你想把它作为数据类型而不是模型类型本身传递。 If that is the case, then I'd recommend using an Object Expression to update the data like so:如果是这种情况,那么我建议使用对象表达式来更新数据,如下所示:

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

Third potential solution第三个可能的解决方案

If you're fine with downcasting , you can shadow your first layer definition like so:如果你对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 }

But usually whenever a downcast is involved that's a code smell, so I'd really recommend constructing a new instance of the interface instead.但通常每当涉及向下转换时,就会产生代码异味,因此我真的建议改为构建接口的新实例。

I never could do this the way I wanted to--by using the ILayer interface to update and return the record type it was associated with.我永远无法以我想要的方式做到这一点——通过使用 ILayer 接口来更新和返回与之关联的记录类型。 I would be most interested in a better way to do this.我最感兴趣的是更好的方法来做到这一点。

What I did end up doing was simply to define three specific functions, one for each type as:我最终所做的只是定义了三个特定的函数,每个类型一个:

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} 

with usage as:用法如下:

{ m with DocumentLayer = documentRadioButton; 
                      WritingLayer = BringToTopWritingLayer documentRadioButton m.WritingLayer;
                      ImageLayer = BringToTopImageLayer documentRadioButton m.ImageLayer;
                      ChartLayer = BringToTopChartLayer documentRadioButton m.ChartLayer}

This seems highly redundant, but it does seem to compile correctly.这看起来非常多余,但它似乎可以正确编译。

A better answer would be most appreciated.一个更好的答案将不胜感激。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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