如何集中抽象(接口)类型的F#定义IComparable的 [英] How to centrally define IComparable on abstract (interface) types in F#

查看:151
本文介绍了如何集中抽象(接口)类型的F#定义IComparable的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题是怎么样的一个新的水平<一的href="http://stackoverflow.com/questions/895769/f-set-using-custom-class">http://stackoverflow.com/questions/895769/f-set-using-custom-class - 我想定义IComparable的一个通用接口

This question is kind of the next level of http://stackoverflow.com/questions/895769/f-set-using-custom-class -- I want to define IComparable for a generic interface.

我有任意一组的其中实现共享元数据交换的接口类型, ITree 。我想在这些类型来比较,仅使用 ITree 暴露的数据。

I have an arbitrary set of types which implement a shared metadata exchange interface, ITree. I want to compare across these types, using only the exposed data in ITree.

我知道这东西是不完全地道的F#,但我想互操作与现有的C#和VB code,所以我想用.NET接口和比较可能的话。

I realize this stuff is not exactly idiomatic F#, but I'm trying to interop with existing C# and VB code, so I want to use .NET interfaces and comparison where possible.

open System
open System.Collections.Generic

// Simplified "generic" metadata type that all implementers agree on
type ITree =
  abstract Path: string with get, set
  abstract ModifyDate: DateTime with get, set

type Thing1(path, date) =
  interface ITree with
    member x.Path = path
    member x.ModifyDate = date

// In reality, the types implementing ITree are going to
// come from different external assemblies
type Thing2(path, date) =
  interface ITree with
    member x.Path = path
    member x.ModifyDate = date

let d1 = DateTime.Now
let d2 = DateTime.Now.AddMinutes(-2.0)
let xs : seq<ITree> = Seq.cast [ Thing1("/stuff", d1); Thing1("/dupe", d1); Thing1("/dupe", d1) ]
let ys : seq<ITree> = Seq.cast [ Thing2("/stuff", d2); Thing2("/dupe", d1) ]

// Then I would like to take advantage of F# Sets
// to do comparison across these things
let xset = Set.ofSeq xs
let yset = Set.ofSeq ys

let same = Set.intersect xset yset
let diffs = (xset + yset) - same

现在实际的问题:这并不能编译,因为 ITree 还没有实施 IComparable的。我需要自定义比较,与时钟偏斜,最终其他的东西帮助。

Now the actual problem: this does not compile because ITree doesn't yet implement IComparable. I need a custom comparison that helps with clock skew and eventually other things.

有没有一种方法可以让我在 ITree 定义比较函数的直接,使所有其他组件不需要去想它,而只需提供他们的数据?

Is there a way I can define the comparison function on ITree directly so that all the other assemblies don't need to think about it, and can just provide their data?

如果我尝试做

type ITree =
  abstract Path: string with get, set
  abstract ModifyDate: DateTime with get, set
    interface IComparable<ITree> with
      let Subtract (this: ITree) (that: ITree) =
        this.ModifyDate.Subtract(that.ModifyDate)
      match compare (this.Path, this.ParentPath) (that.Path, this.ParentPath) with
      | 0 ->
        // Paths are identical, so now for a stupid timespan comparison
        match abs (Subtract this that).TotalSeconds with
        | x when x > 60.0  -> int x
        | _ -> 0
      | x -> x

编译器认为 ITree 不再是一个抽象的接口,或者一些混乱。

The compiler thinks ITree is no longer an abstract interface, or something confusing.

现在,我可以创建所有的实现者必须共享一个基础型的,但我不想这样做,因为这些其他类型的真的只是需要公开他们的数据在该接口上,就已经存在,而且可能已经有一个基类由于某些其他原因。

Now, I could create a base type that all of the implementors must share, but I don't want to do that because those other types really just need to expose their data on this interface, they already exist, and may already have a base class for some other reason.

也许我可以使用的IComparer&LT; T&GT; ,像

type ITreeComparer =      
  interface IComparer<ITree> with
    member x.Compare(this, that) = ...

但我不知道如何告诉设置... 函数使用的IComparer。

But then I have no idea how to tell the Set... functions to use that IComparer.

(我假设,一旦我弄清楚如何申请的IComparer&LT; T&GT; ,同样的方法,将工作的IEqualityComparer&LT; T&GT; 需要。)

(I assume that once I figure out how to apply IComparer<T>, the same methods will work for IEqualityComparer<T> as needed.)


编辑:我可以做

let x = new HashSet<ITree>(a |> Seq.cast<ITree>, new ITreeEqualityComparer())

要使用普通的.NET集合,这应该是对这个问题不够好;但是,我还是想知道是否有更好的方法做我想要做的事情。

To use the normal .NET collections, which should be good enough for this problem; however, I would still like to know if there's a better way to do what I'm trying to do.

推荐答案

您需要创建一个包装类型,如果你想存储在F#的数据集(集不设计定制IComparers工作)。所以,你可以做例如。

You'll need to create a wrapper type if you want to store the data in an F# Set (Set is not designed to work with custom IComparers). So you could do e.g.

type TreeWithComparer(tree:ITree) =
    member this.Data = tree
    interface IComparable with ...
        // define the custom logic you need

,然后存储在设置这些包装对象。

and then store those wrapper objects in the Set.

这篇关于如何集中抽象(接口)类型的F#定义IComparable的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆