...或者,如何通过它们实现的接口过滤一系列类?F#相当于Enumerable.OfType <'a>
假设我有一个从Foo继承的对象序列,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);
}
}
}
我可以使用LINQ从F#:
let mergeFoosIntoList (foos:seq<#Foo>) (dest:IList<'a>) =
System.Linq.Enumerable.OfType<'a>(foos)
|> Seq.iter dest.Add
不过,我觉得应该有一个更惯用的方式来完成它。我认为这会工作...
let mergeFoosIntoList (foos:seq<#Foo>) (dest:IList<'a>) =
foos
|> Seq.choose (function | :? 'a as x -> Some(x) | _ -> None)
|> Seq.iter dest.Add
然而,编译器抱怨:? 'a
- 告诉我:
这个运行时强制或类型的型式检验“B为”一个涉及基于不确定型在这个节目点之前的信息。某些类型不允许运行时类型测试。需要进一步的类型注释。
我找不出什么更多类型的注释添加。接口'a
和#Foo
之间没有任何关系,只是Foo的一个或多个子类实现了该接口。而且,除了它们全部由Foo的子类实现之外,不同接口之间可以以'a
传递的不同接口之间没有关系。
只要你们其中一位善良的人指出我失踪的明显的事情,我就热切地期待自己在脑海中闪过。
该诀窍。谢谢! – 2010-03-26 05:51:32
@布莱恩 - 但你会走这条路?在这种情况下,OfType似乎更漂亮... – Benjol 2010-03-26 10:17:51
如果仅仅是语法问题而不是性能问题,那么使用'typeType <'a>'函数来扩展Seq模块就足够简单了。然后,方法体将会是:'pets |> Seq.ofType <'a> |> Seq.iter dest.Add' – 2010-03-26 16:46:25