Getting started with NAV and .Net Interop – Part 4
Once more into the breach
Jeez, Part
4 already?
Last time
in Part 3 we imported files using streams and learned a bit more about .Net and
our stamina to read boring code. The previous example was a tad bigger than the
first one, but now we’ll wrap that into an even bigger example! Exampleception
!!
Import all files in a
folder
We have all
done
this before. When you want to import a file you make a Record
variable on the File record. Filter it, loop over it, build your filename, and
import it. Something like this:
lv_ImportPath := 'C:\Import'; //You get this
from Setup or the user of course
//Filter
lt_Files.SETRANGE(Path,lv_ImportPath);
lt_Files.SETRANGE("Is a file",TRUE);
lt_Files.SETFILTER(Name,'*.csv');
//Loop
IF lt_Files.FINDSET THEN BEGIN
REPEAT
//Build file path and import file
UNTIL
lt_Files.NEXT = 0;
END;
I’ve always
found this solution clunky when it works. Sometimes it won’t. We can do better
right? RIGHT!
So we
Google “c# read
files in directory”:
à
// Process all files in
the directory passed in, recurse on any directories
// that are found, and
process the files they contain.
public static void ProcessDirectory(string targetDirectory)
{
// Process the list of files found in the
directory.
string[] fileEntries =
Directory.GetFiles(targetDirectory, ".csv");
foreach(string fileName in fileEntries)
ProcessFile(fileName);
}
// Insert logic for
processing found files here.
public static void ProcessFile(string path)
{
Console.WriteLine("Processed file '{0}'.", path);
}
So what’s
happening here?
-
Process
them (in our case import them)
With some
rewriting and some additional Googling we can come to the following
DotNet-powered C/AL:
ldn_Filenames :=
ldn_Directory.GetFiles(lv_FilePath, '*.csv');
ldn_Enumerator := ldn_Filenames.GetEnumerator();
WHILE ldn_Enumerator.MoveNext() DO BEGIN;
lv_FileName
:= ldn_Enumerator.Current;
//Import
file
END;
A soapbox about
Enumerators
You see me
using an Enumerator there to loop through the Array. “But Vincent” you’ll say
“why not define an int-variable and do a FOR-loop until the Array’s Length property
minus 1. Wouldn’t that be more like the C# example?”. And I’ll say “No”.
Because the above C/AL code describes what the foreach in the C# loop does behind the scenes:
-
It
gets an Enumerator from the collection
-
It
asks the enumerator to fetch the next item
-
If
the enumerator comes up blank, the loop is done
The big
difference here is:
The
loop does not need to know how many items there are in the collection
I used the
“emphasis” style for that! Why? Because it’s important: If the loop does not
care how many elements there are in the collection it doesn’t need a count.
Because some collections only know their count by, sometimes painstakingly
slow, enumerating over all their elements. Sometimes collections can only be
enumerated once and they’re gone. So an enumerator goes for the simplest
loop-construction: start the loop, get each item, and end the loop.
This is a
pattern used throughout .Net programming: If you can help it, don’t enumerate
collections twice. The code execution is often optimized to quickly find the
next item from the previous one and finding any “random” item from
an index might actually be very slow. So unless you know damn sure the above
isn’t true in your case or you don’t care about speed and efficiency (GASP!).
So yes,
another contrived example intended to teach you about programming things DotNetStyle.

Reacties
Een reactie posten