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