<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4961961706179594548</id><updated>2011-11-27T15:34:09.218-08:00</updated><category term='extending'/><category term='c#'/><category term='regex'/><category term='Assembler'/><category term='linq'/><category term='Opinion'/><category term='Learning'/><category term='.net 3.5'/><category term='Visual Studio 2008 Best Useful'/><category term='C'/><title type='text'>Development Tracker</title><subtitle type='html'>An eclectic assortment of C# .net tidbits.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://dev-tracker.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4961961706179594548/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://dev-tracker.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Phil</name><uri>http://www.blogger.com/profile/08380685717898641758</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_OKVBkI0MFCk/S_knEKwzI-I/AAAAAAAAAAM/70lAan0XE1M/S220/Picture+10.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>5</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4961961706179594548.post-8865651897759752449</id><published>2010-05-23T06:06:00.000-07:00</published><updated>2010-05-23T07:20:27.067-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Learning'/><category scheme='http://www.blogger.com/atom/ns#' term='Assembler'/><category scheme='http://www.blogger.com/atom/ns#' term='Opinion'/><title type='text'>Retrospective Learning</title><content type='html'>&lt;span style="font-family:arial;"&gt;This post was inspired by a question I found on Stack Overflow recently:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;In the theme of the stackoverflow podcast, here's a fun question: should I learn C? I expect Jeff &amp;amp; Joel will have something to say on this.&lt;br /&gt;&lt;br /&gt;Some info on my background:&lt;br /&gt;&lt;br /&gt;•Primarily a Java programmer on "enterprisy" systems.&lt;br /&gt;•Favorite languages: python, scheme&lt;br /&gt;•7 years programming experience&lt;br /&gt;•A very small amount of C++ experience, practically no C experience&lt;br /&gt;•No immediate "need" to learn C&lt;br /&gt;So should I learn C? If so, why? If not, why?&lt;/blockquote&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;My answer was essentially &lt;/span&gt;&lt;a href="http://stackoverflow.com/questions/296/should-i-learn-c/2576349#2576349"&gt;&lt;span style="font-family:arial;"&gt;no&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family:arial;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family:arial;"&gt;Over the last year or two I have come to the conclusion that technology simply advances too quickly for a single person to learn everything he or she may need &lt;em&gt;ahead of time&lt;/em&gt;. But the real question is do we need to?&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:arial;"&gt;Case in point: A little over a year ago I was job hunting and I had to sit a brain bench* test in C# .net 2.0. I'd just passed the development fundamentals MCP in .net 2.0 and I felt like I had a good handle on the subject so I fired up the brain bench website and started the test.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:arial;"&gt;The first question had me reeling; it was so obscure, so specific, and so &lt;i&gt;difficult&lt;/i&gt; it nearly blew my mind. I mentally shook myself and decided to skip to the next question. Again, so difficult I couldn't begin to answer it. The questions seemed to require the testee to have a very fine grained knowledge of the .net 2.0 documentation. I'd studied enough to pass an MCP, but there's no way I could remember every esoteric detail of the entire framework...&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:arial;"&gt;Now I'm in a bit of a panic; I'm job hunting and I don't want a poor score in this test to destroy my reputation. I mean I've already been developing for a few years with mostly positive feedback from my peers - I like to think I'm pretty good at what I do!&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Arial;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;strong&gt;What are the rules for Brainbench tests?&lt;/strong&gt;&lt;br /&gt;Unlike many standardized tests, individuals are encouraged to use reference materials [...]&lt;/blockquote&gt;&lt;p&gt;&lt;span style="font-family:arial;"&gt;The &lt;a href="http://www.brainbench.com/xml/bb/common/indfaqs.xml#bbtests_and_methodology_rules"&gt;test rules&lt;/a&gt; state that references can be used, but the test must be completed by the testee alone. There are 3 minutes per question and the clock is rapidly counting down on &lt;em&gt;impossible question #3&lt;/em&gt;. I didn't imagine I'd have to, but I fire up the msdn website and do a quick search... Success! I select the correct answer from the options and move on to &lt;em&gt;impossible question #4&lt;/em&gt;. Again the msdn holds the key to victory.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:arial;"&gt;So I traverse the sequence of 26 remaining impossible questions and manage to find an answer to all of them. In the end I achieve a pretty decent score. My transcript number is 7736779 if you're interested in taking a look (&lt;/span&gt;&lt;a href="http://brainbench.com/"&gt;&lt;span style="font-family:arial;"&gt;brainbench.com&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family:arial;"&gt;). &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:arial;"&gt;Which brings me back to my original question: Is there a difference between knowing something and being able to find out in less than 3 minutes? Or, if I can find the correct answer to a seemingly impossible question in less than 3 minutes is that functionally equivalent to &lt;em&gt;knowing&lt;/em&gt; the answer? Is there any point in forcing ourselves to study?&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;&lt;span style="font-family:arial;"&gt;Or am I just lazy?&lt;/span&gt;&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:arial;"&gt;* In my opinion brain bench tests are artificially difficult and utterly fail to measure a person's abillity to develop software. &lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4961961706179594548-8865651897759752449?l=dev-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-tracker.blogspot.com/feeds/8865651897759752449/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dev-tracker.blogspot.com/2010/05/retrospective-learning.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4961961706179594548/posts/default/8865651897759752449'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4961961706179594548/posts/default/8865651897759752449'/><link rel='alternate' type='text/html' href='http://dev-tracker.blogspot.com/2010/05/retrospective-learning.html' title='Retrospective Learning'/><author><name>Phil</name><uri>http://www.blogger.com/profile/08380685717898641758</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_OKVBkI0MFCk/S_knEKwzI-I/AAAAAAAAAAM/70lAan0XE1M/S220/Picture+10.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4961961706179594548.post-4070082560399598130</id><published>2009-08-22T09:25:00.000-07:00</published><updated>2009-08-22T09:58:16.421-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Visual Studio 2008 Best Useful'/><title type='text'>The 7 Essential Visual Studio Tools</title><content type='html'>Visual Studio 2008 is the best of the development environments that I've had the pleasure of working with so far. For all that people enjoy putting them down, in my opinion the developers at Microsoft have delivered an excellent product that is both fast and easy to use! (Which isn't to say that it can't be &lt;a href="http://www.jetbrains.com/resharper/"&gt;improved&lt;/a&gt; - argument vs format string validation is sweet!) This week I'm posting about some of the useful goodies that come with using Visual Studio - things that you technically don't need to know to get the job done but are very handy anyway. I'm listing them in the order that I personally use most frequently:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Find all references. Lists everywhere that a method or variable is used, including the definition. This is really useful when you're trying to work out where a variable is being assigned, or cleared. Right click a method or variable and select Find all references.&lt;/li&gt;&lt;li&gt;Extract method. You've written a bunch of code that gets the job done but it's all inline. It looks horrible, and it's not reusable. Highlight all the code you'd like to break out into a new method, right click and select Extract method. Provide a method name and Visual Studio will create a method for you and even specify the parameters and return value!&lt;/li&gt;&lt;li&gt;The Exceptions window. Press alt + ctrl + e to show this window. Not sure where exactly an exception is being thrown from? Check the Common Language Runtime option in this window and then execute the code.&lt;/li&gt;&lt;li&gt;Call stack window. While debugging, lets you see at a glance the path of method calls that have been made to get you to your current point in the code. Double clicking a method in this window takes you to where the method was called, and let's you see the state of all the local variables. Really handy for debugging. Access through the Debug &gt; Windows menu.&lt;/li&gt;&lt;li&gt;Threads window. While debugging, lets you see how many threads you have executing. Double clicking a thread in this window takes you to its current point of execution in the code. Also accessed through the Debug &gt; Windows menu.&lt;/li&gt;&lt;li&gt;Automatic unit testing. Right click in your code and select Create unit tests... This brings up a dialog that lets you pick which methods to write unit tests for. Visual Studio will then generate a basic unit test for every method you select.&lt;/li&gt;&lt;li&gt;Record/play macro. So you need to perform a &lt;span id="SPELLING_ERROR_0" class="blsp-spelling-corrected"&gt;repetitive&lt;/span&gt; typing operation on your code. Hit shift + &lt;span id="SPELLING_ERROR_1" class="blsp-spelling-error"&gt;ctrl&lt;/span&gt; + r to start recording a macro, perform the operation, and hit shift + &lt;span id="SPELLING_ERROR_2" class="blsp-spelling-error"&gt;ctrl&lt;/span&gt; + r again. Now every time you press shift + &lt;span id="SPELLING_ERROR_3" class="blsp-spelling-error"&gt;ctrl&lt;/span&gt; + p visual studio will perform your typing operation again!&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;That's probably enough to get a fresh faced youngster up to speed. I'm sure any old hands out there have plenty more to add to this list.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4961961706179594548-4070082560399598130?l=dev-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-tracker.blogspot.com/feeds/4070082560399598130/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dev-tracker.blogspot.com/2009/08/7-essential-visual-studio-tools.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4961961706179594548/posts/default/4070082560399598130'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4961961706179594548/posts/default/4070082560399598130'/><link rel='alternate' type='text/html' href='http://dev-tracker.blogspot.com/2009/08/7-essential-visual-studio-tools.html' title='The 7 Essential Visual Studio Tools'/><author><name>Phil</name><uri>http://www.blogger.com/profile/08380685717898641758</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_OKVBkI0MFCk/S_knEKwzI-I/AAAAAAAAAAM/70lAan0XE1M/S220/Picture+10.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4961961706179594548.post-1335883194029263818</id><published>2009-08-10T03:00:00.000-07:00</published><updated>2009-08-10T04:58:42.709-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='.net 3.5'/><category scheme='http://www.blogger.com/atom/ns#' term='extending'/><title type='text'>Forrays into Linq #2 - Effective use of Extension Methods</title><content type='html'>&lt;p&gt;Today I'm talking a little bit about extension methods - where they come from, how to implement them and what I feel they are good for.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Extension methods were added to the .net framework to streamline native support for Linq. As you probably already know, Linq methods can be used on any object implementing the IEnumerable or IQueryable interfaces. What you may not have noticed is that the IEnumerable and IQueryable interfaces don't know anything about Linq. If you think about it, the easiest way to make objects that implement these interfaces accessible to Linq would have been to simply add method definitions to them. Then when a person creates a class that implements one or more of these interfaces they would simply create all the methods defined in the interface. Ctrl + '.' makes that a snap, no? Well it would if there weren't more Linq methods than you can shake a stick at. So, the clever people at Microsoft decided it would be best to expose the Linq methods in an entirely new way.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;So, now that we have a new way of creating functionality how do we actually do it? Well, the syntax is simple if not entirely obvious in what it is actually doing. (Personally I feel that .net 3.5 has introduced a lot of ugliness into C# all in the name of Linq; one of the reasons I left C++ for C# was that there were less symbols cluttering up the code. Referencing and dereferencing pointers, accessing members and methods of an object through a pointer, and all that didn't make C++ particularly accessible. But I digress.) Let's say we want to add a method to the generic List class. I think it would be quite nice if we had a IsNullOrEmpty method like the static String method of the same name: &lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: Consolas, "Courier New", Courier, Monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .alt&lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;List&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; myListOfStrings;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (myListOfStrings.IsNullOrEmpty())&lt;br /&gt;  &lt;span class="kwrd"&gt;return&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;To do this we must first create a public, static class that houses our event methods - the name of the class is unimportant to the compiler but we should give it a good name so we know what's going on when we come back to it in 6 months time. Then we add a public, static method where the first parameter uses the keyword 'this':&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;pre&gt;&lt;/pre&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyListExtensions&lt;br /&gt;{&lt;br /&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsNullOrEmpty&amp;lt;T&amp;gt;(&lt;span class="kwrd"&gt;this&lt;/span&gt; List&amp;lt;T&amp;gt; thisList)&lt;br /&gt;  {&lt;br /&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (thisList == &lt;span class="kwrd"&gt;null&lt;/span&gt; || thisList.Count == 0)&lt;br /&gt;      &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;A quick explanation of the method footprint: The first parameter is the instance of the object type you are extending. The 'this' keyword tells visual studio and the compiler that the method is an extension method for the type List&lt;t&gt;. Next time you call up intellisense for a generic List object it will include this method with the (extension) tag. You can define as many parameters as you want after the 'this' parameter and have any return type. Interestingly the IsNullOrEmpty method on the String class is static because normally if you try to call a method, or access a property, on a null object you will get a NullReferenceException. This demonstrates that although extension methods look a lot like instance methods, they are fundamentally very different.&lt;/p&gt;&lt;p&gt;Some things to keep in mind when writing extension methods:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Extension methods with the same footprint as existing methods will not get called. Try extending the Object class with a method called IsNullOrEmpty. If you use that method on the String type your extension method won't be called - the existing method will be.&lt;/li&gt;&lt;li&gt;Create at least one separate namespace for your extension methods. It's probably worth subdividing your extensions namespace by type/functionality. That way you and your colleagues will only have to browse through the extension methods you are explicitly interested in while coding.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Personally I think extension methods are very useful in making code more readable. For instance, when we use Events one of the things we always have to do is check for subscribers. Ie:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (MyEvent != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;  MyEvent(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; EventArgs());&lt;/pre&gt;&lt;p&gt;It's a pattern that is used everywhere but it really is ugly and not particularly human-readable. Now though, we can create an extension method on the EventHandler&lt;teventargs&gt; class and then write code that would perhaps look more like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (MyEvent.HasSubscribers())&lt;br /&gt;  MyEvent(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="kwrd"&gt;new&lt;/span&gt; EventArgs());&lt;/pre&gt;&lt;p&gt;Much better!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4961961706179594548-1335883194029263818?l=dev-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-tracker.blogspot.com/feeds/1335883194029263818/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dev-tracker.blogspot.com/2009/08/forrays-into-linq-2-effective-use-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4961961706179594548/posts/default/1335883194029263818'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4961961706179594548/posts/default/1335883194029263818'/><link rel='alternate' type='text/html' href='http://dev-tracker.blogspot.com/2009/08/forrays-into-linq-2-effective-use-of.html' title='Forrays into Linq #2 - Effective use of Extension Methods'/><author><name>Phil</name><uri>http://www.blogger.com/profile/08380685717898641758</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_OKVBkI0MFCk/S_knEKwzI-I/AAAAAAAAAAM/70lAan0XE1M/S220/Picture+10.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4961961706179594548.post-5125893483473166829</id><published>2009-07-15T09:41:00.000-07:00</published><updated>2009-08-10T04:59:52.717-07:00</updated><title type='text'>Working with Windows - Converting local paths to UNC format</title><content type='html'>This week I'm posting a solution to a problem that I couldn't find an answer to using the internet, which is to say converting a local folder path to its UNC equivalent. The problem was borne from a system that used a central platform (server) for exporting data that is controlled remotely. So if a user wants something from the system he or she provides a path that tells it where to put that something. So far so good, but if the user gives a rooted path of the format "C:\..." the requested item gets saved to the server's local file system, which is a high security zone. Not good.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So onto the solution - a way to get a folder path from the user that can only be a fully qualified UNC path. As with most problems we start by looking around to see if there are any technologies that can make our job easier. The chances are somebody out there has done this, or something very similar, before and been kind enough to post it in the internet. A quick inspection of the &lt;em&gt;FolderBrowserDialog&lt;/em&gt; reveals it can be initialised in such a way to give the user a view of his or her &lt;em&gt;My Network Places&lt;/em&gt;, thus forcing the user to select a network path. Sounds good but in practise we find that if the user selects a shared folder from the &lt;em&gt;My Network Places&lt;/em&gt; that points to a folder on his or own local system the &lt;em&gt;FolderBrowserDialog&lt;/em&gt; will automatically convert it to a local file path. So close, but so tragically flawed (for our purposes)!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Scanning the &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.folderbrowserdialog.aspx"&gt;documentation&lt;/a&gt; for the &lt;em&gt;FolderBrowserDialog&lt;/em&gt; doesn't reveal a way to stop it from being too damned clever, so we begin the hunt for a way to change the local file path &lt;em&gt;back&lt;/em&gt; into a UNC file path. We already know that the path points to an existing network resource so we don't need to do any validation, we just need to run a conversion on it. After a little digging at &lt;a href="http://www.pinvoke.net/default.aspx/netapi32/NetShareEnum.html"&gt;pinvoke&lt;/a&gt; we discover a method in the &lt;em&gt;netapi32&lt;/em&gt; library that will give us information on all of the shared folders on the local system including the name of the shared resource on the network. The method we're interested in is called &lt;em&gt;EnumNetShares&lt;/em&gt; and someone has even been kind enough to post a C# implementation. So, now we can build up a picture of the required workflow:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Show the user the &lt;em&gt;My Network Places&lt;/em&gt; &lt;em&gt;FolderBrowserDialog&lt;/em&gt; to get a UNC folder path.&lt;/li&gt;&lt;li&gt;If the file path provided by the &lt;em&gt;FolderBrowserDialog&lt;/em&gt; has the format '\\MachineName\...' finish here.&lt;/li&gt;&lt;li&gt;Use the &lt;em&gt;EnumNetShares netapi32&lt;/em&gt; method to retrieve information on all the shares on the local machine.&lt;/li&gt;&lt;li&gt;Find a share that has a local path that matches the beginning of the path picked by the user.&lt;/li&gt;&lt;li&gt;Build up a UNC path from the local machine name, the path of the share, and the path picked by the user.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Mission complete. For those of you who prefer to read code rather than paragraphs a code snippet is listed below. I copied the GetEnumShares class from the pinvoke site.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: Consolas, "Courier New", Courier, Monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .alt&lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.IO;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Runtime.InteropServices;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; ConsoleApplication1&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;class&lt;/span&gt; Utilities&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;/// Takes a local file path and translates it into a UNC file path where possible.&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;/// &amp;lt;param name="path"&amp;gt;Path to convert to UNC.&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;If possible UNC path otherwise the original file path.&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetUniversalPath(&lt;span class="kwrd"&gt;string&lt;/span&gt; path)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; universalPath = path;&lt;br /&gt;            &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;            {&lt;br /&gt;                DirectoryInfo di = &lt;span class="kwrd"&gt;new&lt;/span&gt; DirectoryInfo(path);&lt;br /&gt;                GetNetShares gns = &lt;span class="kwrd"&gt;new&lt;/span&gt; GetNetShares();&lt;br /&gt;                &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (GetNetShares.ShareInfo shareInfo &lt;span class="kwrd"&gt;in&lt;/span&gt; gns.EnumNetShares(&lt;span class="str"&gt;"127.0.0.1"&lt;/span&gt;))&lt;br /&gt;                {&lt;br /&gt;                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (shareInfo.Path.Length &amp;gt; 0 &amp;amp;&amp;amp; path.StartsWith(shareInfo.Path, StringComparison.OrdinalIgnoreCase))&lt;br /&gt;                    {&lt;br /&gt;                        &lt;span class="kwrd"&gt;string&lt;/span&gt; pathRemainder = path.Substring(shareInfo.Path.Length);&lt;br /&gt;                        &lt;span class="kwrd"&gt;return&lt;/span&gt; BuildPath(String.Concat(&lt;span class="str"&gt;@"\\", Environment.MachineName), shareInfo.ShareName, pathRemainder);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            catch&lt;br /&gt;            { }&lt;br /&gt;&lt;br /&gt;            return universalPath;&lt;br /&gt;        }&lt;br /&gt;        public static string BuildPath(string pathPart1, string pathPart2, string pathPart3)&lt;br /&gt;        {&lt;br /&gt;            StringBuilder pathBuilder = new StringBuilder();&lt;br /&gt;            pathBuilder.Append(pathPart1);&lt;br /&gt;            if (pathPart1[pathPart1.Length - 1] != '\\')&lt;br /&gt;                pathBuilder.Append("&lt;/span&gt;\\&lt;span class="str"&gt;");&lt;br /&gt;            pathBuilder.Append(pathPart2);&lt;br /&gt;            if (pathPart2[pathPart2.Length - 1] != '\\')&lt;br /&gt;                pathBuilder.Append("&lt;/span&gt;\\&lt;span class="str"&gt;");&lt;br /&gt;            pathBuilder.Append(pathPart3);&lt;br /&gt;&lt;br /&gt;            return pathBuilder.ToString();&lt;br /&gt;        }&lt;br /&gt;        public class GetNetShares&lt;br /&gt;        {&lt;br /&gt;            #region External Calls&lt;br /&gt;            [DllImport("&lt;/span&gt;Netapi32.dll&lt;span class="str"&gt;", SetLastError = true)]&lt;br /&gt;            static extern int NetApiBufferFree(IntPtr Buffer);&lt;br /&gt;            [DllImport("&lt;/span&gt;Netapi32.dll", CharSet = CharSet.Unicode)]&lt;br /&gt;            &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;extern&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; NetShareEnum(&lt;br /&gt;                 StringBuilder ServerName,&lt;br /&gt;                 &lt;span class="kwrd"&gt;int&lt;/span&gt; level,&lt;br /&gt;                 &lt;span class="kwrd"&gt;ref&lt;/span&gt; IntPtr bufPtr,&lt;br /&gt;                 &lt;span class="kwrd"&gt;uint&lt;/span&gt; prefmaxlen,&lt;br /&gt;                 &lt;span class="kwrd"&gt;ref&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; entriesread,&lt;br /&gt;                 &lt;span class="kwrd"&gt;ref&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; totalentries,&lt;br /&gt;                 &lt;span class="kwrd"&gt;ref&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; resume_handle&lt;br /&gt;                 );&lt;br /&gt;            &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;            &lt;span class="preproc"&gt;#region&lt;/span&gt; External Structures&lt;br /&gt;            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]&lt;br /&gt;            &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;struct&lt;/span&gt; ShareInfo&lt;br /&gt;            {&lt;br /&gt;                &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ShareName;&lt;br /&gt;                &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;uint&lt;/span&gt; ShareType;&lt;br /&gt;                &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Remark;&lt;br /&gt;                &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;uint&lt;/span&gt; Permissions;&lt;br /&gt;                &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;uint&lt;/span&gt; MaxUses;&lt;br /&gt;                &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;uint&lt;/span&gt; CurrentUses;&lt;br /&gt;                &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Path;&lt;br /&gt;                &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Password;&lt;br /&gt;&lt;br /&gt;                &lt;span class="kwrd"&gt;public&lt;/span&gt; ShareInfo(&lt;span class="kwrd"&gt;string&lt;/span&gt; netname, &lt;span class="kwrd"&gt;uint&lt;/span&gt; type, &lt;span class="kwrd"&gt;string&lt;/span&gt; remark, &lt;span class="kwrd"&gt;uint&lt;/span&gt; permissions, &lt;span class="kwrd"&gt;uint&lt;/span&gt; max_uses, &lt;span class="kwrd"&gt;uint&lt;/span&gt; current_uses, &lt;span class="kwrd"&gt;string&lt;/span&gt; path, &lt;span class="kwrd"&gt;string&lt;/span&gt; password)&lt;br /&gt;                {&lt;br /&gt;                    ShareName = netname;&lt;br /&gt;                    ShareType = type;&lt;br /&gt;                    Remark = remark;&lt;br /&gt;                    Permissions = permissions;&lt;br /&gt;                    MaxUses = max_uses;&lt;br /&gt;                    CurrentUses = current_uses;&lt;br /&gt;                    Path = path;&lt;br /&gt;                    Password = password;&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;            &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;uint&lt;/span&gt; MAX_PREFERRED_LENGTH = 0xFFFFFFFF;&lt;br /&gt;            &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; SuccessCode = 0;&lt;br /&gt;            &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;enum&lt;/span&gt; NetErrorResults : &lt;span class="kwrd"&gt;uint&lt;/span&gt;&lt;br /&gt;            {&lt;br /&gt;                Success = 0,&lt;br /&gt;                BASE = 2100,&lt;br /&gt;                UnknownDevDir = (BASE + 16),&lt;br /&gt;                DuplicateShare = (BASE + 18),&lt;br /&gt;                BufTooSmall = (BASE + 23),&lt;br /&gt;            }&lt;br /&gt;            &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;enum&lt;/span&gt; SHARE_TYPE : &lt;span class="kwrd"&gt;uint&lt;/span&gt;&lt;br /&gt;            {&lt;br /&gt;                DiskTree = 0,&lt;br /&gt;                PrintQ = 1,&lt;br /&gt;                Device = 2,&lt;br /&gt;                IPC = 3,&lt;br /&gt;                Special = 0x80000000,&lt;br /&gt;            }&lt;br /&gt;            &lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;ShareInfo&amp;gt; EnumNetShares(&lt;span class="kwrd"&gt;string&lt;/span&gt; Server)&lt;br /&gt;            {&lt;br /&gt;                List&amp;lt;ShareInfo&amp;gt; ShareInfos = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;ShareInfo&amp;gt;();&lt;br /&gt;                &lt;span class="kwrd"&gt;int&lt;/span&gt; entriesread = 0;&lt;br /&gt;                &lt;span class="kwrd"&gt;int&lt;/span&gt; totalentries = 0;&lt;br /&gt;                &lt;span class="kwrd"&gt;int&lt;/span&gt; resume_handle = 0;&lt;br /&gt;                &lt;span class="kwrd"&gt;int&lt;/span&gt; nStructSize = Marshal.SizeOf(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ShareInfo));&lt;br /&gt;                IntPtr bufPtr = IntPtr.Zero;&lt;br /&gt;                StringBuilder server = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringBuilder(Server);&lt;br /&gt;                &lt;span class="kwrd"&gt;int&lt;/span&gt; ret = NetShareEnum(server, 2, &lt;span class="kwrd"&gt;ref&lt;/span&gt; bufPtr, MAX_PREFERRED_LENGTH, &lt;span class="kwrd"&gt;ref&lt;/span&gt; entriesread, &lt;span class="kwrd"&gt;ref&lt;/span&gt; totalentries, &lt;span class="kwrd"&gt;ref&lt;/span&gt; resume_handle);&lt;br /&gt;                &lt;span class="kwrd"&gt;if&lt;/span&gt; (ret == SuccessCode)&lt;br /&gt;                {&lt;br /&gt;                    IntPtr currentPtr = bufPtr;&lt;br /&gt;                    &lt;span class="kwrd"&gt;for&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt; i = 0; i &amp;lt; entriesread; i++)&lt;br /&gt;                    {&lt;br /&gt;                        ShareInfo shi1 = (ShareInfo)Marshal.PtrToStructure(currentPtr, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ShareInfo));&lt;br /&gt;                        ShareInfos.Add(shi1);&lt;br /&gt;                        currentPtr = &lt;span class="kwrd"&gt;new&lt;/span&gt; IntPtr(currentPtr.ToInt32() + nStructSize);&lt;br /&gt;                    }&lt;br /&gt;                    NetApiBufferFree(bufPtr);&lt;br /&gt;                    &lt;span class="kwrd"&gt;return&lt;/span&gt; ShareInfos;&lt;br /&gt;                }&lt;br /&gt;                &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;                {&lt;br /&gt;                    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;ShareInfo&amp;gt;();&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4961961706179594548-5125893483473166829?l=dev-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-tracker.blogspot.com/feeds/5125893483473166829/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dev-tracker.blogspot.com/2009/07/working-with-windows-converting-local.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4961961706179594548/posts/default/5125893483473166829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4961961706179594548/posts/default/5125893483473166829'/><link rel='alternate' type='text/html' href='http://dev-tracker.blogspot.com/2009/07/working-with-windows-converting-local.html' title='Working with Windows - Converting local paths to UNC format'/><author><name>Phil</name><uri>http://www.blogger.com/profile/08380685717898641758</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_OKVBkI0MFCk/S_knEKwzI-I/AAAAAAAAAAM/70lAan0XE1M/S220/Picture+10.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4961961706179594548.post-3844921511062780363</id><published>2009-07-09T04:32:00.000-07:00</published><updated>2009-08-12T07:55:41.124-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='regex'/><category scheme='http://www.blogger.com/atom/ns#' term='linq'/><category scheme='http://www.blogger.com/atom/ns#' term='c#'/><category scheme='http://www.blogger.com/atom/ns#' term='.net 3.5'/><title type='text'>Forays into Linq - Querying a text file.</title><content type='html'>Hi! I'm Phil and this is my first ever programming themed blog post. I am a software developer of around 7 years currently working in .net 3.5. It is my intention to post about programming matters that I find interesting as I encounter them. Hopefully the result will be as enjoyable to you as it is to me!&lt;br /&gt;&lt;br /&gt;To start off I'd like to blog about a program I wrote recently. It was interesting to me as I was able to leverage a couple existing technologies to write something quite concise.&lt;br /&gt;&lt;br /&gt;We had a problem with some "corrupted" text files - some MS Office documents had been converted to text files and apparently contained both the body of the text and the accompanying meta data. What was needed was a text file that contained just the body of the text.&lt;br /&gt;&lt;br /&gt;A cursory look over some of the files showed that the meta data was always 72 characters wide and consisted of alphanumeric characters and the symbols '/', and '+'. In that case it is a simple matter to write a &lt;a href="http://msdn.microsoft.com/en-us/library/az24scfc(VS.71).aspx"&gt;Regular Expression&lt;/a&gt; that will match a line of of meta data:&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: Consolas, "Courier New", Courier, Monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .alt&lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;br /&gt;&lt;/style&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="rem"&gt;// regex recognises a row of corrupted data. &lt;/span&gt;&lt;br /&gt;Regex corruptedText = &lt;span class="kwrd"&gt;new&lt;/span&gt; Regex(&lt;span class="str"&gt;@"^[a-zA-Z0-9+/]{72}$"&lt;/span&gt;); &lt;/pre&gt;So, we have a method for spotting lines of meta data and now what we need to do is iterate over every line of the file and copy all the lines that don't match to a new text file. Or do we? It would be nice if we could just ask the file to give me all the lines of text that don't match the regular expression, wouldn't it? It turns out that using Linq we can do exactly that!&lt;br /&gt;&lt;br /&gt;Linq can be used to query any collection that implements the IEnumerable&lt;&gt; interface. If we had such a collection that had an item for each line of text we could create a Linq expression that used the regular expression to give us all the lines of text that weren't meta data:&lt;br /&gt;&lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: Consolas, "Courier New", Courier, Monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .alt&lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;br /&gt;&lt;/style&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;IEnumerable&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt; goodlines = textFile.Where(dataLine =&amp;gt; !corruptedText.IsMatch(dataLine)).Select(dataLine =&amp;gt; dataLine); &lt;/pre&gt;Where &lt;em&gt;textFile&lt;/em&gt; represents a collection implementing &lt;em&gt;IEnumerable&lt;string&gt;&lt;/em&gt;. This will result in every instance of dataLine that doesn't get matched by the regular expression being placed in the &lt;em&gt;goodlines&lt;/em&gt; collection. Now we have a complete method for outputting the data we want from a collection all that's left is to get the text from the file into said collection. It turns out that this is also easy enough to almost be trivial: &lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: Consolas, "Courier New", Courier, Monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .alt&lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;/// File reader that enumerates every line of text in a file.&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; StreamReaderEx : StreamReader, IEnumerable&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; StreamReaderEx(&lt;span class="kwrd"&gt;string&lt;/span&gt; path)&lt;br /&gt;        : &lt;span class="kwrd"&gt;base&lt;/span&gt;(path)&lt;br /&gt;    { }&lt;br /&gt;    &lt;span class="preproc"&gt;#region&lt;/span&gt; IEnumerable Members&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; IEnumerator GetEnumerator()&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; dataLine;&lt;br /&gt;        &lt;span class="kwrd"&gt;while&lt;/span&gt; ((dataLine = &lt;span class="kwrd"&gt;base&lt;/span&gt;.ReadLine()) != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;            &lt;span class="kwrd"&gt;yield&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; dataLine;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;    &lt;span class="preproc"&gt;#region&lt;/span&gt; IEnumerable Members&lt;br /&gt;    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;string&lt;/span&gt; dataLine;&lt;br /&gt;        &lt;span class="kwrd"&gt;while&lt;/span&gt; ((dataLine = &lt;span class="kwrd"&gt;base&lt;/span&gt;.ReadLine()) != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;            &lt;span class="kwrd"&gt;yield&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; dataLine;&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;Let's take a minute to look at what we have here. The &lt;em&gt;StreamReaderEx&lt;/em&gt; class inherits from the &lt;em&gt;StreamReader&lt;/em&gt; class and implements the &lt;em&gt;IEnumerable&lt;string&gt;&lt;/em&gt; interface. Inheriting from the &lt;em&gt;StreamReader&lt;/em&gt; class gives us all the functionality we need to read text files from the file system, and implementing the &lt;em&gt;IEnumerator&lt;/em&gt; interface lets Linq in on the action too. We want our Linq expression to query each line of data so our implementation of &lt;em&gt;IEnumerable&lt;&gt;.GetEnumerator()&lt;/em&gt; should do a &lt;em&gt;yield return&lt;/em&gt; on each line of text from the text file. Using the &lt;em&gt;yield return&lt;/em&gt; keywords means that the compiler will generate the enumerator class for us in the background.&lt;br /&gt;&lt;br /&gt;So there we have it! The result is we have an application that is mostly declarative rather than imperative. This means that rather than write detailed instructions for every step of the process we can just ask for a specific result and the compiler will interpret that request and transform it into detailed instructions for us. The advantages of being declarative rather than imperative are that the code is faster to write, easier to maintain, and more concise, and the compiler can make optimisations as it sees fit. The disadvantage is that we lose control of the fine details of the execution.&lt;br /&gt;&lt;br /&gt;The full code listing is shown below for the sake of completeness. Unfortunately all the formatting around the code gets messed up by the blog editor; I'm looking into a way of tidying that up. &lt;style type="text/css"&gt;&lt;br /&gt;.csharpcode, .csharpcode pre&lt;br /&gt;{&lt;br /&gt; font-size: small;&lt;br /&gt; color: black;&lt;br /&gt; font-family: Consolas, "Courier New", Courier, Monospace;&lt;br /&gt; background-color: #ffffff;&lt;br /&gt; /*white-space: pre;*/&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.csharpcode pre { margin: 0em; }&lt;br /&gt;&lt;br /&gt;.csharpcode .rem { color: #008000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .kwrd { color: #0000ff; }&lt;br /&gt;&lt;br /&gt;.csharpcode .str { color: #006080; }&lt;br /&gt;&lt;br /&gt;.csharpcode .op { color: #0000c0; }&lt;br /&gt;&lt;br /&gt;.csharpcode .preproc { color: #cc6633; }&lt;br /&gt;&lt;br /&gt;.csharpcode .asp { background-color: #ffff00; }&lt;br /&gt;&lt;br /&gt;.csharpcode .html { color: #800000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .attr { color: #ff0000; }&lt;br /&gt;&lt;br /&gt;.csharpcode .alt&lt;br /&gt;{&lt;br /&gt; background-color: #f4f4f4;&lt;br /&gt; width: 100%;&lt;br /&gt; margin: 0em;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;.csharpcode .lnum { color: #606060; }&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections.Generic;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.IO;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Text.RegularExpressions;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; CleanTextFiles&lt;br /&gt;{&lt;br /&gt;    &lt;span class="kwrd"&gt;class&lt;/span&gt; Program&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Main(&lt;span class="kwrd"&gt;string&lt;/span&gt;[] args)&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="rem"&gt;// regex recognises a row of corrupted data. Regex &lt;/span&gt;&lt;br /&gt;            corruptedText = &lt;span class="kwrd"&gt;new&lt;/span&gt; Regex(&lt;span class="str"&gt;@"^[a-zA-Z0-9+/]{72}$"&lt;/span&gt;);&lt;br /&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; corruptedFilePath &lt;span class="kwrd"&gt;in&lt;/span&gt; Directory.GetFiles(&lt;span class="str"&gt;@"D:\Data\"))&lt;br /&gt;            {&lt;br /&gt;                string cleanedFilePath = String.Concat(Path.GetDirectoryName(corruptedFilePath),&lt;br /&gt;                                            @"&lt;/span&gt;\clean\",&lt;br /&gt;                                            Path.GetFileName(corruptedFilePath));&lt;br /&gt;                Directory.CreateDirectory(Path.GetDirectoryName(cleanedFilePath));&lt;br /&gt;                &lt;span class="kwrd"&gt;using&lt;/span&gt; (StreamReaderEx reader = &lt;span class="kwrd"&gt;new&lt;/span&gt; StreamReaderEx(corruptedFilePath))&lt;br /&gt;                &lt;span class="kwrd"&gt;using&lt;/span&gt; (StreamWriter writer = &lt;span class="kwrd"&gt;new&lt;/span&gt; StreamWriter(cleanedFilePath))&lt;br /&gt;                {&lt;br /&gt;                    WriteLines(reader, writer, corruptedText);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;/// Write every line of text from reader into writer that doesn't match the corruptedText regex pattern. &lt;/span&gt;&lt;br /&gt;        &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; WriteLines(StreamReaderEx reader, StreamWriter writer, Regex corruptedText)&lt;br /&gt;        {&lt;br /&gt;            IEnumerable goodlines = reader.Where(dataLine =&amp;gt; !corruptedText.IsMatch(dataLine)).Select(dataLine =&amp;gt; dataLine);&lt;br /&gt;            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt; goodLine &lt;span class="kwrd"&gt;in&lt;/span&gt; goodlines)&lt;br /&gt;                writer.WriteLine(goodLine);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;/// File reader that enumerates every line of text in a file.&lt;/span&gt;&lt;br /&gt;    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;class&lt;/span&gt; StreamReaderEx : StreamReader, IEnumerable&lt;br /&gt;    {&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; StreamReaderEx(&lt;span class="kwrd"&gt;string&lt;/span&gt; path)&lt;br /&gt;            : &lt;span class="kwrd"&gt;base&lt;/span&gt;(path)&lt;br /&gt;        { }&lt;br /&gt;        &lt;span class="preproc"&gt;#region&lt;/span&gt; IEnumerable Members&lt;br /&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; IEnumerator GetEnumerator()&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; dataLine;&lt;br /&gt;            &lt;span class="kwrd"&gt;while&lt;/span&gt; ((dataLine = &lt;span class="kwrd"&gt;base&lt;/span&gt;.ReadLine()) != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;                &lt;span class="kwrd"&gt;yield&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; dataLine;&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;        &lt;span class="preproc"&gt;#region&lt;/span&gt; IEnumerable Members&lt;br /&gt;        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()&lt;br /&gt;        {&lt;br /&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; dataLine;&lt;br /&gt;            &lt;span class="kwrd"&gt;while&lt;/span&gt; ((dataLine = &lt;span class="kwrd"&gt;base&lt;/span&gt;.ReadLine()) != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;                &lt;span class="kwrd"&gt;yield&lt;/span&gt; &lt;span class="kwrd"&gt;return&lt;/span&gt; dataLine;&lt;br /&gt;        }&lt;br /&gt;        &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4961961706179594548-3844921511062780363?l=dev-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dev-tracker.blogspot.com/feeds/3844921511062780363/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://dev-tracker.blogspot.com/2009/07/forays-into-linq-querying-text-file.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4961961706179594548/posts/default/3844921511062780363'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4961961706179594548/posts/default/3844921511062780363'/><link rel='alternate' type='text/html' href='http://dev-tracker.blogspot.com/2009/07/forays-into-linq-querying-text-file.html' title='Forays into Linq - Querying a text file.'/><author><name>Phil</name><uri>http://www.blogger.com/profile/08380685717898641758</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://3.bp.blogspot.com/_OKVBkI0MFCk/S_knEKwzI-I/AAAAAAAAAAM/70lAan0XE1M/S220/Picture+10.jpg'/></author><thr:total>0</thr:total></entry></feed>
