It's really very simple to get LINQ running with ArcObjects. All you have to do is add an extension method to either ICursor or IFeatureCursor like so:
public static class ICursorExtensions {
public static IEnumerable<IRow> AsEnumerable(this ICursor source) {
Func<IRow> next = () => source.NextRow();
IRow current = next();
while (current != null) {
yield return current;
current = next();
}
}
}
With your new extension method in hand, you can unleash LINQ on your ArcObjects code. You can now write code like this:
Int32 count = cursor.AsEnumerable().Count();
Or, you could write a query expression against two cursor objects:
var resultSeq =
from x in cursor1.AsEnumerable()
from y in cursor2.AsEnumerable()
where x.get_Value(0) = y.get_Value(0)
select new { Left = x, Right = y };
You can do a similar thing in F#:
type ICursor with
member c.AsEnumerable() =
seq {
let next = c.NextRow
let current = ref (next())
while !current <> null do
yield !current
do current := next()
}
let count = cursor.AsEnumerable() |> Seq.length
Sure beats manually manipulating an enumerator, doesn't it?
3 comments:
Love to see a vb.net version. Have trouble with the code conversion.
Unfortunately, there is no direct equivalent to this code in Visual Basic since the language does not support a "yield" operation. But, you can gather all of the rows in a List and pass the list out of the method:
-----------------------------
Imports System.Collections.Generic
Imports System.Runtime.CompilerServices
Public Module ICursorExtensions
<Extension()> _
Public Function AsEnumerable(ByVal source As ICursor) As IEnumerable(Of IRow)
Dim nextRow As Func(Of IRow) = Function() source.NextRow()
Dim rows As New List(Of IRow)
Dim current As IRow = nextRow()
Do While current IsNot Nothing
rows.Add(current)
current = nextRow()
Loop
Return rows
End Function
End Module
-----------------------------
Hope that helps!
Great discussion! By the way, the latest version of VB does support iterator (Yield Return).
Even with the older version, you can do the same thing if declaratively like this:
Public Function AsEnumerable(ByVal source As ICursor) As IEnumerable(Of IRow)
Return Enumerable.Range(0, Integer.MaxValue) _
.Select(Function(n) source.NextRow()) _
.TakeWhile(Function(r) r IsNot Nothing)
End Function
Pleas also try my OR Mapping tool!
Demo
Code + Tool
It's written in C# though.
Post a Comment