Showing posts with label c#. Show all posts
Showing posts with label c#. Show all posts

Wednesday, April 15, 2009

Australian Postcode Validation

I was recently porting and updating some old Pascal postcode validation to C# and thought i'd stick it up here.

To tell the truth, the Pascal code is more concise. Pascal, VB, Ruby etc have means to test a range of values in a single case statement. Unfortunately C# doesn't provide for this contingency, hence the "fall through's" in the case blocks.

Anyway, maybe someone might find this useful as there are a few "interesting" situations with the ACT and NSW.



 1     public static string GetState(string postCode) {
 2       if (!IsValidPostCodeFormat(postCode))
 3         return "";
 4
 5       switch (postCode[0]) {
 6         case '5': return "SA";             // SA:  5000-5999
 7         case '3':
 8         case '8': return "VIC";            // VIC: 3000-3999, 8000-8999
 9         case '4':
10         case '9': return "QLD";            // QLD: 4000-4999, 9000-9999
11         case '6': return "WA";             // WA:  6000-6999
12         case '7': return "TAS";            // TAS: 7000-7999
13         case '1': return "NSW";            // NSW: 1000-1999
14
15         case '0':
16           switch (postCode[1]) {
17             case '8':
18             case '9': return "NT";         // NT:  0800-0999
19             case '2': return "ACT";        // ACT: 0200-0299
20             default: return "";
21           }
22
23         case '2':
24           int tmp = Int32.Parse(postCode);
25           if ((tmp >= 2600 && tmp <= 2618) || (tmp >= 2900 && tmp <= 2920))
26             return "ACT";                  // ACT: 2600-2618, 2900-2920
27           else if ((tmp >= 2000 && tmp <= 2599) || (tmp >= 2619 && tmp <= 2898)
28                                                 || (tmp >= 2921 && tmp <= 2999))
29             return "NSW";                  // NSW: 2000-2599, 2619-2898, 2921-2999
30           else return "";
31
32         default: return "";
33       }
34     }
35
36     private static bool IsValidPostCodeFormat(string postCode) {
37       int tmp;
38       if (String.IsNullOrEmpty(postCode) || postCode.Length != 4 
39                                          || !Int32.TryParse(postCode, out tmp))
40         return false;
41
42       return true;
43     }
44




Wednesday, September 24, 2008

Returning lambda's from a ternary in C#

In the midst of some mad refactoring I came across something similar to the following snippet:

 1 if (count == 0)
 2   choice.Finish = result => { return; };
 3 else
 4   choice.Finish = result => { letter.MailMerge(result); };

Looked like a decent candidate for refactoring with a ternary / conditional operator:

 7 choice.Finish = (count == 0) ? result => { return; }
 8                              : result => { letter.MailMerge(result); };

Type of conditional expression cannot be determined because there is no implicit conversion between 'lambda expression' and 'lambda expression'

Hold your horses, say what?

For some reason the only way to fool it through the compiler is to cast one of the expressions (it doesn't seem to matter which one) to the expected return type.

11 choice.Finish = (count == 0) ? (TypeDelegate<int>) (result => { return; })
12                              : result => { letter.MailMerge(result); };


Go figure!

Saturday, June 14, 2008

Why?

css:

.mainMenuHeader {color:#FFFFFF;}
.mainMenuHeader:hover {color:#F26540;}

xaml:

<Style x:Key="mainMenuHeader">
  <Setter Property="Control.Foreground" Value="#FFFFFF" />
  <Style.Triggers>
    <Trigger Property="Control.IsMouseOver" Value="True">
      <Setter Property="Control.Foreground" Value="#F26540" />
    </Trigger>
  </Style.Triggers>
</Style>

Wednesday, October 17, 2007

C# .NET Regular Expressions gotcha

I sure do love me some regular expressions but haven't really had the need in any of my C# code until now.

A few things did catch me out though, in particular the constructor for the Regex class.

The constructor signature I'm interested in is this one: (string pattern, RegexOptions options). All well and good until you want to set multiple options!

Now I might be slightly naive but why doesn't the constructor use the params keyword allowing it to accept a variable number of RegexOptions? The constructor would then look something like (string pattern, params RegexOptions[] options). I think this follows the LOLA, unlike the current method of passing multiple regex options to the constructor.

Oh, guess how you are supposed to do it? Via a bitwise OR of the enum values ofcourse! Like my NUnit fun, at least I can now just get on with it.


 1 Regex matchFieldValue =
 2   new Regex(@"
 3     (?<Field>\w+) #capture 1 or more word characters to the named group 'Field'
 4     \s*=\s*       #followed by 0 or more spaces, an = sign and 0 or more spaces
 5     (?<Value> '   #match an apostrophe
 6         ([^'] |   #match 0 or more of any character that is not an ' OR
 7          ''.)*    #double apostrophe's followed by any character          
 8     ')            #match the closing ' and capture to named group 'Value'
 9             ",
10              RegexOptions.Compiled |
11              RegexOptions.IgnoreCase |
12              RegexOptions.IgnorePatternWhitespace);

Friday, October 12, 2007

NUnit configuration woes

I've been going through writing NUnit tests for a .NET web app I'm writing at work and all was going well until I hit some code that was using the ConfigurationManager.

1 private static readonly string CONNECTION_STRING =
2  ConfigurationManager.ConnectionStrings["DBConn"].ConnectionString;

For backgrounds sake I've created a test dll that sits outside the web app that calls a dll used by the web app. The connection string information is stored in Web.config.

Whenever NUnit loaded up the tests requiring that connection it barfed this at me:

Test.TestDataAccessUtility.GetNameValueTOList : System.TypeInitializationException : The type initializer for 'DataAccessUtility' threw an exception.
----> System.NullReferenceException : Object reference not set to an instance of an object.


Nice, this essentially means that ConfigurationManager had crapped itself.

ConfigurationManager.ConnectionStrings.Count was returning 1.

ConfigurationManager.ConnectionStrings[0].ConnectionString sent back a conn string for a SQLExpress db with some configuration string I sure didn't set.

It would appear that the NUnit loads it's config file over your application's config file.

To fix, I just replaced the contents of the NUnit config file: Project1.config with the contents of my Web.config. There could be a better solution, but it's working now and I can move on with my life.

Friday, September 21, 2007

Code Voyeur

I like perusing public code repositories, be they CVS/SVN/Mercurial/Git whatever. I'm not sure if this is some kind of sick code voyeurism fetish but I think it's kind of healthy in degrees. It's a good place to pick up tricks. Kind of like doing the weekly ruby quiz but looking at the code before you know what the task is and seeing how closely you think they correlate to the spec.

Scott Hanselman is also on the kick of reading other peoples code to become a better developer, could it be the path to enlightment?

It dawned upon me that at work I have rarely had the need to tread outside my projects. All this time i've been searching far and wide for great code when I had a veritable treasure trove of unread code right under my nose.

We have a VB contractor doing some work for us and I caught wind that someone asked him to do it in C# ASP.NET. Wow. Might not be so bad I thought. So I had a look in SVN and came across this:


 1     public static string Proper(string StringIn) {
 2       string Temp = StringIn;
 3       if (Temp.CompareTo(String.Empty) != 0) {
 4
 5         char[] Delimiter = { ' ' };
 6         string[] Words = Temp.Split(Delimiter);
 7         Temp = String.Empty;
 8
 9         for (int i = Words.GetLowerBound(0); i <= Words.GetUpperBound(0); i++)
10           if (Words[i].Trim().CompareTo(String.Empty) != 0)
11             Temp += Words[i].Substring(0, 1).ToUpper() +
12                     Words[i].Substring(1).ToLower() + " ";
13         return Temp;
14       }
15       else
16         return String.Empty;
17     }
18


Apart from the upper case local variable names, in-efficient string concatenation and re-inventing the wheel, the dude did alright. Absolute respect to him, he's smart, he got it working, but it is obvious that C# is not his native tongue. That is textbook VB in C#.

Here is something roughly equivalent I came up with that produces the same output (don't lambast me for not getting the current culture, "en-AU" does weird shit that "en" doesn't) :)


1     using System.Globalization;
2     public static string TitleCase(string str) {
3       return String.IsNullOrEmpty(str) ? String.Empty
4              : new CultureInfo("en").TextInfo.ToTitleCase(str.ToLower());
5     }


It's not his fault really. He was asked to code in a language he wasn't familiar with and he got by. But what he did was speak English in down-town Nairobi.

Now I don't know what my point is but just look at the API's if you are using an unfamiliar language. I'm not shit-hot with C#, give me C, Java or Ruby and I've got a fighting chance. The thing is I'd assume that .NET would provide a way to title case a string. Instead of re-inventing the wheel I did a google search and came across the TextInfo class. You think he would have twigged that if VB has StrConv there might be something vaguely similar in C#.

Moral of the story, if you're asked to code in a language you are not familiar with, knock it back or make it clear it might not look pretty. But i guess who doesn't like getting paid?

Tuesday, August 28, 2007

"Ruby off the Rails?" quid pro quo

I came across Ruby off the Rails? by Paul Turner and he issued a challenge at the end of his post, and I bit :)

Read it here (including the comments) then come back for my some-what larger response.

Begin communique:

I agree with you that Microsoft adding more and more languages to the framework is a bad idea. J# anyone? . Their ploy is to lower barrier to entry, so what you end up with is some developers using anything but C#, because, well why bother learning it if you don't have to. Have you tried proposing C#.NET to a VB developer when they can use VB.NET? I have, it's not fun. It might just be me but I question the maintainability of an application written in 7 different languages.

To answer your question:

Read the following with the caveat of using the "right tool for the right job". Obviously if you are targetting a windows desktop app, it is hard to trump WinForms. However i think .NET is licked in every other category.

  1. Portability (Mono still doesn't implement the full .NET 2.0 API)

  2. Expressiveness of language:

  3. 1    for (int i = 0; i < 5; i++) {
    2      Console.Out.Write("c# loop ");
    3    }

    vs.

    1 5.times { print "ruby loop " }

  4. Cost $$$$$$$$$$$$$$$

  5. MSDN documentation is, well crap, contrast:

  6. http://msdn2.microsoft.com/en-us/library/system.io.file(vs.85).aspx
    and
    http://java.sun.com/javase/6/docs/api/java/io/File.html

  7. Closed source / Open standard


I can safely say that you are the first Microsoft proponent that I have come across that knows the difference between open-source and open-standard :). Some people claim that .NET is open-source. No; it's a huge difference. Java is open-source: http://www.sun.com/2006-1113/feature/. Ruby is open-source: http://www.ruby-lang.org/en/LICENSE.txt. But you hit the nail on the head C# is an open standard: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf.

This might not be a kicker for a lot of people, but it is to me. I like being able to delve into source and see what's going on and change it to suit me. This is how i found a bug in the Sun implementation of the CachedRowSet, i thought i was going insane but i was able to get in there and figure why it wasn't working and then report it. Kudos for the open-standard, but one up it and go the whole hog.

I was also working as a government employee when I discovered that bug. If the source hadn't been open I would not have been able to temporarily patch it and get on with what I was doing.

I also have to disagree about the 'purity' of keeping SQL code in SQL Server. It's fine if you have resigned yourself to paying for SQL Server subscriptions the rest of your life. But i'd like to bet on a bit of flexibility and write ANSI compliant SQL that i could quite easily drop into Postgres or any other db for that matter. Ofcourse there are extenuating circumstances (performance reasons and the like) to dabble in sql server extensions, but it is a rarity. I wish i also had the energy to go the age old 'dynamic sql vs stored procedures' argument with you too :)

Rather than bemoan the fact that is IronRuby, maybe have a look at it, who knows you might give up your C# day job :)