如何创建包含具有公共超类的对象的F#列表?

我有两个功能,水平和垂直,用于布局控件。他们的工作方式如下:
let verticalList = vertical [new TextBlock(Text = "one"); 
                             new TextBlock(Text = "two"); 
                             new TextBlock(Text = "three")]
现在verticalList是一个垂直显示三个文本块的控件:
one
two
three
以下是定义:
let horizontal controls = 
    let wrap = new WrapPanel() in
    List.iter (wrap.Children.Add >> ignore) controls ;
    wrap

let vertical controls = 
    let stack = new StackPanel() in
    List.iter (stack.Children.Add >> ignore) controls ;
    stack
当我组合不同类型时会出现问题:
let foo = vertical [new TextBlock(Text = "Title"); vertical items]
这抱怨列表中的元素不是同一类型。这是事实,但他们有一个共同的超类型(UIElement)。 我知道我可以使用:> UIElement来覆盖列表中的两个项目,但这是一个丑陋的解决方案。 F#可以推断出常见的超类型。如果没有,为什么不呢? 如果看起来很好看会很棒
vertical [X; Y; Z]
不必成为
vertical [(X :> UIElement); (Y :> UIElement); (Z :> UIElement)]
    
已邀请:
有几种方法,包括
type Animal() = class end
type Cat() =
    inherit Animal()
type Dog() =
    inherit Animal()
let animals1 : list<Animal> = [upcast new Cat(); upcast new Dog()]
let animals2 = ([upcast new Cat(); upcast new Dog()] : list<Animal>)
let animals3 = [(new Cat() :> Animal); upcast new Dog()]
animals1:在var声明中键入注释,向上转换每个元素 animals2:在列表表达式上键入注释,向上转换每个元素 animals3:第一个元素的显式类型,upcast rest 在F#的未来版本中,上传很可能变得不必要。 (另见http://cs.hubfs.net/forums/thread/9953.aspx,但没有'新'那里。)     
如果您同意牺牲类型安全性以便于阅读,那么您就是解决方法:
open System
let to_list (tuple: Object) = 
    let rec list_after_index (n: int) = 
        let prop = tuple.GetType().GetMethod("get_Item"+n.ToString())
        match prop with
            | null -> []
            | _ -> prop.Invoke(tuple, [||]) :: list_after_index(n+1)
    match tuple with 
        | :? unit -> []
        | _ when tuple.GetType().FullName.Contains(".Tuple`") -> list_after_index(1)
        | _ -> [tuple]
然后你就可以这样使用它:
> to_list ();;
val it : obj list = []
> to_list (1);;
val it : obj list = [1]
> to_list([], 1, "2", 3.0);;
val it : obj list = [[]; 1; "2"; 3.0]
例如在你的垂直功能内。     
我更喜欢我以前的答案,但在此基础上,如果你有一个应用程序,你不断创建非同质的动物列表,你总是可以做这样的事情:
let Animalize (x:Animal) = x  // define a function to upcast
let animals4 = [ Animalize <| new Cat(); Animalize <| new Dog()]
// or even
let (~++) = Animalize // define a prefix operator to upcast (~ makes it prefix)
let animals5 = [ ++ new Cat(); ++ new Dog()]
最后几乎肯定是滥用操作员,除非你处于一个非常专业的领域,你经常需要这样的强制,你愿意牺牲固有的可读性来实现简洁。     

要回复问题请先登录注册