...或者,如何通过它们实现的接口过滤一系列类?
假设我有一系列从Foo继承的对象,a seq<#Foo>.换句话说,我的序列将包含Foo的四个不同子类中的一个或多个.
每个子类实现一个不同的独立接口,它与其他子类实现的接口不共享.
现在我需要将此序列过滤为仅实现特定接口的项目.
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我可以使用F#中的LINQ:
let mergeFoosIntoList (foos:seq<#Foo>) (dest:IList<'a>) =
System.Linq.Enumerable.OfType<'a>(foos)
|> Seq.iter dest.Add
Run Code Online (Sandbox Code Playgroud)
但是,我觉得应该有一种更惯用的方法来实现它.我以为这会起作用......
let mergeFoosIntoList (foos:seq<#Foo>) (dest:IList<'a>) =
foos
|> Seq.choose (function | :? 'a as x -> Some(x) | _ -> None)
|> Seq.iter dest.Add
Run Code Online (Sandbox Code Playgroud)
然而,编纂者抱怨:? 'a- 告诉我:
从类型'b到'a的这种运行时强制或类型测试涉及基于该程序点之前的信息的不确定类型.某些类型不允许运行时类型测试.需要进一步的类型注释.
我无法弄清楚要添加的更多类型注释.还有的接口之间没有任何关系'a,并#Foo除美孚的一个或多个子类实现该接口.此外,'a除了它们都是由Foo的子类实现之外,可以传入的不同接口之间没有关系.
一旦有一个善良的人指出我一直想念的明显事物,我就急切地期待自己在头脑中咂嘴.
Mar*_*ann 10
你可以这样做:
let foos = candidates |> Seq.filter (fun x -> x :? Foo) |> Seq.cast<Foo>
Run Code Online (Sandbox Code Playgroud)
通常只需添加一个"盒子"即可(例如更改function为fun x -> match box x with),但让我试一试......
是啊; 基本上你不能从一个任意泛型类型转向另一个,但你可以向上转换为System.Object(via box),然后向下转换为你喜欢的任何东西:
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")
Run Code Online (Sandbox Code Playgroud)