如何将 F# 类型提供程序生成的类型公开给 C# 和 XAML
How to expose types generated by an F# Type Provider to C# and XAML
因此,我正在使用 XML Type Provider 从 XML 文档创建类型。
XML 文件中的一个元素具有 Date
属性:
<Edit Date="06/30/2015 16:57:46"
... />
这当然会导致这样的类型:
type Edit =
inherit XmlElement
member Date: DateTime
...
有什么方法可以添加以下代码:
member this.LocalTime
with get() =
this.Date.ToLocalTime()
到结果 Edit
类型?
原因是我从 XAML 绑定到 Edit
的实例,我真的不想为此写一个 IValueConverter
。
编辑:
所以,我才意识到这些类型不适合我的 XAML。相反,我得到了 FSharp.Data.Runtime.BaseTypes.XmlElement
的实例,它们当然甚至不包含我在 F# 代码中看到的属性。我还需要从 C# 代码中使用这些类型,即使在那里我也只得到 XmlElement
s 而没有属性
我知道我可以在 XAML 中使用 XPath 来导航其中的 XElements,但我仍然需要一种方法来以强类型方式访问生成的对象模型,无论是从 C# 还是 XAML.
编辑2:
所以现在我写了一个 Type Extension 这样的:
type Catalog.Edit with
member this.LocalTime with get() = this.Date.ToLocalTime()
我在 F# 代码中看到的成员就像生成的成员一样。然而,这种方法有两个缺点:
1 - 它迫使我将我的 namespace
更改为 module
,这不太方便,因为这些类型都是从 C# 代码中使用的,在那里我看到它们是嵌套的 classes 进入模块 class,这是丑陋的。
2 - 我仍然无法从 C# 或 XAML.
中看到此成员(也不是生成的成员)
在所描述的场景中实现此功能的正确方法是什么?
XML 和 JSON 的 F# 数据类型提供程序是 erasing 类型提供程序。这意味着您在 F# 中使用它们时看到的类型在运行时实际上并不存在 - 它们被替换为一些底层运行时表示(此处 XmlElement
)。
不幸的是,这意味着这些类型不是 真正的 类型,因此它们仅对 F# 可见。
我的建议是使用 F# 记录定义一个简单的域类型,并将您的数据从 XML 加载到您的记录中。这需要做更多的工作,但它也给了你更多的安全性,因为你明确定义了结构——所以如果你的 XML 改变了,你就会知道你需要改变你的 XAML代码也是!
它应该像这样简单:
type Edit = { Date : DateTime }
let GetData () =
let doc = MyXmlType.Load("somefile.xml")
seq { for item in doc.Edits -> { Date = item.Date } }
因此,我正在使用 XML Type Provider 从 XML 文档创建类型。
XML 文件中的一个元素具有 Date
属性:
<Edit Date="06/30/2015 16:57:46"
... />
这当然会导致这样的类型:
type Edit =
inherit XmlElement
member Date: DateTime
...
有什么方法可以添加以下代码:
member this.LocalTime
with get() =
this.Date.ToLocalTime()
到结果 Edit
类型?
原因是我从 XAML 绑定到 Edit
的实例,我真的不想为此写一个 IValueConverter
。
编辑:
所以,我才意识到这些类型不适合我的 XAML。相反,我得到了 FSharp.Data.Runtime.BaseTypes.XmlElement
的实例,它们当然甚至不包含我在 F# 代码中看到的属性。我还需要从 C# 代码中使用这些类型,即使在那里我也只得到 XmlElement
s 而没有属性
我知道我可以在 XAML 中使用 XPath 来导航其中的 XElements,但我仍然需要一种方法来以强类型方式访问生成的对象模型,无论是从 C# 还是 XAML.
编辑2:
所以现在我写了一个 Type Extension 这样的:
type Catalog.Edit with
member this.LocalTime with get() = this.Date.ToLocalTime()
我在 F# 代码中看到的成员就像生成的成员一样。然而,这种方法有两个缺点:
1 - 它迫使我将我的 namespace
更改为 module
,这不太方便,因为这些类型都是从 C# 代码中使用的,在那里我看到它们是嵌套的 classes 进入模块 class,这是丑陋的。
2 - 我仍然无法从 C# 或 XAML.
中看到此成员(也不是生成的成员)在所描述的场景中实现此功能的正确方法是什么?
XML 和 JSON 的 F# 数据类型提供程序是 erasing 类型提供程序。这意味着您在 F# 中使用它们时看到的类型在运行时实际上并不存在 - 它们被替换为一些底层运行时表示(此处 XmlElement
)。
不幸的是,这意味着这些类型不是 真正的 类型,因此它们仅对 F# 可见。
我的建议是使用 F# 记录定义一个简单的域类型,并将您的数据从 XML 加载到您的记录中。这需要做更多的工作,但它也给了你更多的安全性,因为你明确定义了结构——所以如果你的 XML 改变了,你就会知道你需要改变你的 XAML代码也是!
它应该像这样简单:
type Edit = { Date : DateTime }
let GetData () =
let doc = MyXmlType.Load("somefile.xml")
seq { for item in doc.Edits -> { Date = item.Date } }