如何将F#类型提供程序生成的类型公开给C#和XAML

时间:2015-07-22 14:02:55

标签: c# xaml f# type-providers f#-data

所以,我正在使用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

我知道我可以在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#代码中消耗掉的,在那里我将它们视为嵌套类到模块类中,这很难看。

2 - 我仍然无法从C#或XAML中看到这个成员(也不是生成的成员)。

在描述的场景中实现这一点的正确方法是什么?

1 个答案:

答案 0 :(得分:6)

XML和JSON的F#数据类型提供程序是擦除类型提供程序。这意味着从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 } }