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