F#等效于Enumerable.OfType<'a> [英] F# Equivalent to Enumerable.OfType<'a>

查看:83
本文介绍了F#等效于Enumerable.OfType<'a>的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

...或者,如何通过它们实现的接口过滤一系列的类?

比方说,我有一系列对象继承自Foo(seq<#Foo>).换句话说,我的序列将包含Foo的四个不同子类中的一个或多个.

Let's say I have a sequence of objects that inherit from Foo, a seq<#Foo>. In other words, my sequence will contain one or more of four different subclasses of Foo.

每个子类实现一个不同的独立接口,该接口与其他子类实现的接口不共享任何东西.

Each subclass implements a different independent interface that shares nothing with the interfaces implemented by the other subclasses.

现在,我需要将此序列过滤为仅实现特定接口的项目.

Now I need to filter this sequence down to only the items that implement a particular interface.

C#版本很简单:

    void MergeFoosIntoList<T>(IEnumerable<Foo> allFoos, IList<T> dest) 
        where T : class
    {
        foreach (var foo in allFoos)
        {
            var castFoo = foo as T;
            if (castFoo != null)
            {
                dest.Add(castFoo);
            }
        }
    }

我可以使用F#中的LINQ:

I could use LINQ from F#:

    let mergeFoosIntoList (foos:seq<#Foo>) (dest:IList<'a>) =
            System.Linq.Enumerable.OfType<'a>(foos)
            |> Seq.iter dest.Add

但是,我觉得应该有一种更惯用的方式来实现它.我以为这会工作...

However, I feel like there should be a more idiomatic way to accomplish it. I thought this would work...

    let mergeFoosIntoList (foos:seq<#Foo>) (dest:IList<'a>) =
            foos
            |> Seq.choose (function | :? 'a as x -> Some(x) | _ -> None)
            |> Seq.iter dest.Add

但是,编译器抱怨:? 'a-告诉我:

However, the complier complains about :? 'a - telling me:

这种从类型'b到'a的运行时强制或类型测试涉及一个不确定的类型,该类型基于此程序点之前的信息.在某些类型上不允许运行时类型测试.需要进一步的类型注释.

This runtime coercion or type test from type 'b to 'a involves an indeterminate type based on information prior to this program point. Runtime type tests are not allowed on some types. Further type annotations are needed.

我不知道要添加什么类型的注释.接口'a#Foo之间没有任何关系,只是Foo的一个或多个子类实现了该接口.另外,可以作为'a传递的不同接口之间没有关系,除了它们都是由Foo的子类实现的.

I can't figure out what further type annotations to add. There's no relationship between the interface 'a and #Foo except that one or more subclasses of Foo implement that interface. Also, there's no relationship between the different interfaces that can be passed in as 'a except that they are all implemented by subclasses of Foo.

当你们中的一个人指出我所缺少的显而易见的东西时,我会热切地期待着自己的头部.

I eagerly anticipate smacking myself in the head as soon as one of you kind people points out the obvious thing I've been missing.

推荐答案

通常只需添加一个框"就足够了(例如,将function更改为fun x -> match box x with),但是让我尝试一下...

Typically just adding a 'box' is sufficient (e.g. change function to fun x -> match box x with), but let me try it out...

是的;基本上,您不能从一种任意的泛型类型横向转换为另一种泛型,但是您可以向上投射到System.Object(通过box),然后向下投射到任何您喜欢的类型:

Yeah; basically you cannot sideways cast from one arbitrary generic type to another, but you can upcast to System.Object (via box) and then downcast to anything you like:

type Animal() = class end
type Dog() = inherit Animal()
type Cat() = inherit Animal()

let pets : Animal list = 
    [Dog(); Cat(); Dog(); Cat(); Dog()]
printfn "%A" pets

open System.Collections.Generic     

let mergeIntoList (pets:seq<#Animal>) (dest:IList<'a>) = 
    pets 
    |> Seq.choose (fun p -> match box p with  
                            | :? 'a as x -> Some(x) | _ -> None) //'
    |> Seq.iter dest.Add 

let l = new List<Dog>()
mergeIntoList pets l
l |> Seq.iter (printfn "%A")

这篇关于F#等效于Enumerable.OfType&lt;'a&gt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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