Как обновить и вернуть запись с помощью интерфейса в F#

#inheritance #interface #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.Модель, слой изображений.Модель и составитель карт.Модель, которая будет использоваться в качестве:

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

Спасибо вам за ваше внимание.

Комментарии:

1. Сообщение об ошибке означает , что вы, вероятно, забыли open WritingLayer это сделать, поэтому тип записи и ее поля не видны в вашей области видимости.

2. @FyodorSoikin Проблема здесь в том, что мне также понадобится «Модель» слоя диаграмм и слоя изображений. Спасибо.

3. Подождите, так вы просто спрашиваете, как ссылаться на поля записи, не открывая модуль, в котором определена запись?

Ответ №1:

Этот код не будет работать как есть:

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

Это связано с тем, что F# неявно опускается до типа, реализующего интерфейс.

Первое потенциальное решение:

Переключитесь с передачи an ILayer на прямую передачу a 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
 

Третье потенциальное решение

Если вас устраивает понижение, вы можете затенить свое первое 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 }
 

Но обычно всякий раз, когда происходит подавление, это запах кода, поэтому я бы действительно рекомендовал вместо этого создать новый экземпляр интерфейса.

Комментарии:

1. Если я сделаю: пусть BringToTop rb (слой:модель) = как в первом потенциальном решении, я получу сообщение об ошибке «Модель не определена». (Это была моя первая попытка). 🙁

2. Второе потенциальное решение возвращает тип ILayer. Мне нужно, чтобы он вернул тип модели, с которого он начинался. То есть, в идеале, BringToTop будет использоваться как: BringToTop rb m.Слой записи, возвращающий слой записи; Слой изображений BringToTop rb с возвратом слоя изображений; слой диаграмм BringToTop rb с возвратом слоя диаграмм. Мы очень ценим вашу помощь. Спасибо.

3. Пожалуйста, смотрите добавление к первоначальному вопросу. Спасибо.

Ответ №2:

Я никогда не мог сделать это так, как хотел-используя интерфейс 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}
 

Это кажется крайне избыточным, но, похоже, оно компилируется правильно.

Лучший ответ был бы весьма признателен.