Tuesday, July 28, 2009

New Version of Table Data Scripter Released

I have just released a new version of my Table Data Scripter utility, which creates scripts to insert or update data into a Sql Server database, based on data in an existing database.

You can get the new version here.

New in this version;


    Dropped support for Sql 2000.
    Now supports scripting data in ‘schemas’ other than dbo.

    Fixed various bugs.


Sunday, July 26, 2009

Follow Up To “Creating and Raising Events – The Right Way”

Some time ago I made a post about common misunderstandings newcomers to C# have around declaring and raise events. There were two critical items I left out of or have learned since that post;

Race Condition In Standard Pattern

The standard pattern for raising an event that is well published every where looks like this;

    public event EventHandler MyEvent;
    public virtual void OnMyEvent()
    {
      if (MyEvent != null)
        MyEvent(this, new EventArgs());
    }


This is wrong however. While it appears to work, there is a race condition in this code; if a thread switch occurs after the if condition is evaluated and before the event is raised, then all the event handlers could be disconnected which would then lead to a System.NullReferenceException when the code actually tries to raise the event.



To get around this, you must cache the event reference in a local variable and then use the local variable in the code, like this;



    public event EventHandler MyEvent;
    public virtual void OnMyEvent()
    {
      EventHandler eventToRaise = MyEvent;
      if (eventToRaise != null)
        eventToRaise(this, new EventArgs());
    }


By caching a reference to the event before testing or raising it we can guarantee the value won’t change in the case of a thread switch, and therefore we avoid the null reference exception.



Declare Event Argument Properties as Read Only





When creating your own event argument objects it is good practice to ensure any properties you don’t expect to change during the event as read only. The only properties you shouldn’t make read only are ones you expect the event handlers to modify (return values), such as a ‘cancel’ parameter that you check after the event to determine if you should continue with your next operation.



There are two parts to declaring your properties read only. First, if the type of the property is a primitive or immutable type like int or string you should declare the field readonly and allow it to be passed in on the constructor;



  public class MyEventArgs : EventArgs
  {
    private readonly int m_Value;
    public MyEventArgs(int value)
    {
      m_Value = value;
    }
  }


The readonly keyword tells the C# compiler that field can only be set in the constructor of the class, trying to set it anywhere else will result in a compilation error. Note, you shouldn’t do this with non-immutable or primitive types, like other objects as you’ll get compile warnings or code analysis errors because event though the reference can’t be changed the properties on the referenced object can and therefore technically the property value can still change.



The second thing to do, which applies to a read only property of any type, is to ensure the property itself has no setter;



  public class MyEventArgs : EventArgs
  {
    private readonly int m_Value;
    public MyEventArgs(int value)
    {
      m_Value = value;
    }
    public int Value
    {
      get { return m_Value; }
    }
  }


Now you can be sure that no event handler can change the value of your event arguments and cause subsequent event handlers to behave unexpectedly.







Technorati Tags: ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,





Windows Live Tags: Events,Some,items,Race,Condition,Standard,Pattern,event,EventHandler,MyEvent,OnMyEvent,EventArgs,code,System,NullReferenceException,cache,reference,exception,custom,arguments,MyEventArgs,parameter,integer,needs,Argument,Read,practice,operation,result,compilation,error,Note,objects,analysis,Value,handler,newcomers,handlers,errors,eventToRaise,constructor,m_Value







WordPress Tags: Events,Some,items,Race,Condition,Standard,Pattern,event,EventHandler,MyEvent,OnMyEvent,EventArgs,code,System,NullReferenceException,cache,reference,exception,custom,arguments,MyEventArgs,parameter,integer,needs,Argument,Read,practice,operation,result,compilation,error,Note,objects,analysis,Value,handler,newcomers,handlers,errors,eventToRaise,constructor,m_Value







Blogger Labels: Events,Some,items,Race,Condition,Standard,Pattern,event,EventHandler,MyEvent,OnMyEvent,EventArgs,code,System,NullReferenceException,cache,reference,exception,custom,arguments,MyEventArgs,parameter,integer,needs,Argument,Read,practice,operation,result,compilation,error,Note,objects,analysis,Value,handler,newcomers,handlers,errors,eventToRaise,constructor,m_Value

Saturday, July 25, 2009

A Better Way To Print Receipts

There are two reasons I’m writing this post. The first is because I want to clarify some of the requirements I had in Ontempo Store before I write my next Pos .Net post. The second is because I’ve seen a lot of people on the ‘net asking how to drive POS receipt printers and their focus seems to be on how to access the device, which while important, isn’t the only issue you need to consider in a retail application.

With Ontempo Store we were trying to create a world class solution for tier 1 and 2 retailers, which meant merely printing fixed strings on a receipt wasn’t going to be good enough. Printing hard coded text with prices and quantities embedded is often what is shown in sample code, or in questions about how to drive receipt printers. In our case, we had the following additional requirements;

  • Customisation – we need our users to be able to customise parts of printed documents, such as the receipt header and footer, signature slips, terms and conditions for certain sale types, voucher and coupon formats etc. As well as letting them specify text for these things, we need to allow the user customising the receipt to include instructions like bold, underline, cuts, logo prints, barcodes to print etc.

  • Print Preview and Review – we need to be able to view printed information on screen, both before and after it’s printed in a WYSIWYG way. 

  • Print Auditing – we need to be able to store the data sent to the printer. This needs to be done as an audit, and to allow us to quickly reprint or view a transaction, voucher or other document at a later stage and know that we are seeing what was printed originally, not the “current” state. This is particularly important for ‘tax invoices’ which sometimes have legal requirements around re-prints matching the original.

  • Network Printing – we want to be able to print to a ‘shared’ printer. Our networking solution uses an asynchronous message based system, which means we must be able to pass our entire document as a single block of data (a single message). Multiple method calls remoted via one mechanism or another aren’t going to work, or be performant.

So what we came up with is ‘PML’. PML stands for Print Mark-up Language and is a simple way of creating a string that contains all the information needed to format a document for a receipt printer. It’s pretty simple, and most closely resembles XSL in that anything that isn’t a tag or tag data is written out to the printer as is, and xml style tags are used to control formatting.

Here’s some sample PML for a receipt header;

<align value="centre"><logo/><br/></align><align value="centre"><b>Westgate</b><br/><b>Phone</b> 649 555 5555 <b>Fax</b> 649 555 5551<br/>You were served by Yort<br/>GST# 55-555-555</align><br/>Docket #DF654542     18-07-2009 11:33:12<br/><u><repeat count="42"> </repeat></u><br/><br/>

The end result of this would print or preview something like this;

Receipt Header Sample

As an interesting side point, note the use of the ‘repeat’ tag. This tag has nothing to do with sending commands to the printer, but is used to repeat text or a block of PML between it’s opening and closing tags. In the case above it repeats an underlined space character 42 times, effectively drawing a horizontal line. We can also use this to repeat more complicated blocks of text or formatting, or to print multiple copies of an entire document.

So how do we use PML ? The PML for the document content itself is constructed by whatever component of our system is creating the document to be printed, but items like the header and footer of receipts are stored as system settings the user can edit as required, and are just prepended or appended to the beginning or end of the document as required.

We have a class called PrintFormatter (not the best name or design, but I didn’t create the original version and haven’t yet refactored it) which is responsible for parsing the PML. The parsing is done using regular expressions.

The PrintFormatter has two methods of operation. Regardless of which mode is being used, once the PrintFormatter is setup all you need to do to process the PML is pass it to a method called ProcessData.

String Builder Mode

Immediately after the PrintFormatter object is instantiated it is ‘configured’ by calls to a method called AddDirective. This method has several overloads, one that takes a tag name and an escape sequence, one that takes a tag name and two separate escape sequences (one for each of the start and end of the tag) and finally one that takes a tag name and and a delegate.

Whenever the PrintFormatter locates a tag (during the ProcessData method call) it either calls the delegate associated with the tag or replaces the tag and it’s contents with the escape code(s) provided.

In the case of the delegate, the return value replaces the tag and it’s contents. A delegate is usually used when a tag has attributes that alter the escape code that needs to be embedded, like when printing a barcode and you need to specify height, width, symbology etc.

The end result is a string (accessible via a property on the PrintFormatter object) which can be sent directly to the printer assuming an escape code or other embedded sequence is available for all print formatting functions.

Event Mode

Event mode is enabled by setting the UseEventMode property to true. In this case you don’t need to call AddDirective for each supported tag. Instead, the system raises either a ProcessTag, ProcessTagEnd or ProcessText event every time it finds a tag, closed tag, or data to be output as is.

The event arguments for ProcessTag and ProcessTagEnd contain the tag name, tag contents and a list of attribute names and values specified on the tag.

When we’re doing a print preview, we handle these events and alter the current pen/brush and then call DrawString or DrawImage to display the actual content using the current settings. We also have to keep track of the current x and y co-ordinates for where we’re going to print next.

We also had to use this mechanism for printing via Pos .Net, as some Pos .Net commands are escape codes and some are method calls which couldn’t be embedded in a string to be sent to the printer, but still had to be processed in sequence. Also, Pos .Net doesn’t have escape codes to cancel some previous formatting commands, and it resets the print format to ‘normal’ after every call to PrintNormal.

As a result we couldn’t just build up a string with escape codes embedded, but rather had to keep track of the current print state by building a stack of unclosed tags for those commands that are represented by escape codes, and every time we call PrintNormal we prepend the escape sequences to the data being printed. On a tag close we pop last escape code sequence off the stack.  This allows correct processing of PML like this;

<b>Branch : </b> Westgate

Which should be displayed with Branch in bold and Westgate in the ‘normal’ format, like this;

Branch Westgate

The key point though, is that regardless of how the PML is processed we can represent an entire, formatted, document as a string. This allows us to store it, ship it across the network as a single data block, or re-print it in it’s original state at any time.

So, when designing a retail system that prints receipts or other documents on a receipt or sip printer, spend as much time architecting the printing processes as the rest of your application. They can be just as important, and failure to do so can leave you with a real problem when you try to implement other features later.


Technorati Tags: ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

Windows Live Tags: Formatting,Devices,Pos .Net,PosPrinter,PML,Print,Receipts,Ontempo,receipt,solution,tier,code,Customisation,documents,header,footer,signature,sale,voucher,coupon,user,logo,Preview,Review,WYSIWYG,printer,transaction,Network,mechanism,Language,Docket,commands,component,items,PrintFormatter,version,expressions,operation,mode,ProcessData,Builder,AddDirective,sequence,contents,width,Event,UseEventMode,ProcessTag,ProcessTagEnd,ProcessText,output,arguments,events,DrawImage,PrintNormal,Branch,failure,features,printers,retailers,users,sequences,codes

WordPress Tags: Formatting,Devices,Pos .Net,PosPrinter,PML,Print,Receipts,Ontempo,receipt,solution,tier,code,Customisation,documents,header,footer,signature,sale,voucher,coupon,user,logo,Preview,Review,WYSIWYG,printer,transaction,Network,mechanism,Language,Docket,commands,component,items,PrintFormatter,version,expressions,operation,mode,ProcessData,Builder,AddDirective,sequence,contents,width,Event,UseEventMode,ProcessTag,ProcessTagEnd,ProcessText,output,arguments,events,DrawImage,PrintNormal,Branch,failure,features,printers,retailers,users,sequences,codes

Blogger Labels: Formatting,Devices,Pos .Net,PosPrinter,PML,Print,Receipts,Ontempo,receipt,solution,tier,code,Customisation,documents,header,footer,signature,sale,voucher,coupon,user,logo,Preview,Review,WYSIWYG,printer,transaction,Network,mechanism,Language,Docket,commands,component,items,PrintFormatter,version,expressions,operation,mode,ProcessData,Builder,AddDirective,sequence,contents,width,Event,UseEventMode,ProcessTag,ProcessTagEnd,ProcessText,output,arguments,events,DrawImage,PrintNormal,Branch,failure,features,printers,retailers,users,sequences,codes

Sunday, July 19, 2009

Pos .Net Series, Post #1 – Introduction & The Good Stuff

Microsoft Pos .Net is (almost certainly) the best way to control point of sale peripherals from your .NET retail application. It allows you to easily control receipt and slip printers, barcode scanners, cash drawers, MICR (magnetic ink character recognition), MSR (magnetic swipe reader), line display devices, and more.

Some time ago my boss and I decided we wanted to build Pos .Net drivers for the point of sale application I work on, Ontempo Store. Unfortunately we had trouble finding suitable service objects at the time, and as we only needed to drive a receipt printer and cash drawer so we implemented an alternate solution. Recently we got some new hardware on short-term loan, and it came with OPOS drivers (which are compatible with Pos .Net). We’ve also had better success in finding Pos .Net service objects for our existing hardware, recently and so I spent some time building a new set of drivers while we still had the loan hardware to test with.

This is a first in a series of posts on my experiences with Pos .Net. On the whole, it’s pretty good, but there are a few pitfalls to be aware of (a lot of these aren’t really Pos .Net’s fault, but you have to live with them anyway so I’m blogging about them).

Pos .Net has three really great features;

  • It allows you to control many different brands and model of devices in a device independent way… you don’t have to build a separate driver or write different code for each specific peripheral. While OPOS also does this, OPOS implementations are often built using COM components, which are an old technology and not ideal for use for .Net languages if you can help it.
  • It has a neat plug and play system that allows automatic detection of (connecting and disconnecting) USB devices, with no additional configuration of the device required to use it.
  • If your application is running on a terminal server but your devices are plugged into each local client, Pos .Net can access the devices back across the Remote Desktop connection, allowing your system to operate like a client application with regards to devices.

Pos .Net is the Microsoft implementation of the UPOS (Unified Point Of Service) standard, which is the follow up to the original OPOS standard, but features like the plug and play support have been added specifically by Microsoft as added extras.

In order for Pos .Net to work with a given device you must have either a native .net ‘Service Object’, or a legacy OPOS service object. Service objects are the ‘middleware’ that contain the brand/model specific code for a particular peripheral.

Once you have an appropriate service object (and you can write your own if need be) controlling a device with Pos .Net is very easy. Performance is generally great (although some what dependent on the service object).

If you’re new to Pos .Net and looking to get started I recommend downloading the Pos .Net SDK and looking at it’s samples. It has some good samples for dealing with barcode scanners and building your own service objects. If you want some samples for printers and cash drawers then I recommend downloading the Epson OPOS ADK for .Net. To get that, you’ll need to register at www.epsonexpert.com, and once logged in go to Application Development –> OPOS then scroll to the bottom of the page to find the download links. Even if you’re not using Epson hardware, the Epson samples will work (because Pos .Net is device independent) and they cover most aspects of using the Pos .Net PosPrinter class. There’s also this Microsoft hands on lab which is quite good too.

For Pos .Net resources and links see my earlier post.

If you’re wondering why you should use Pos .Net over other methods (such as using the Win32 print API) for driving printers and cash drawers, here are a few good reasons;

  • Universal escape codes… even Epson’s escape codes don’t necessarily work the same on all models, and across different brands there’s even more variation.
  • Better status handling and error detection. Detect conditions cover open, paper low, paper out, offline etc.
  • Capability reporting, know whether your device can report it’s status, print bitmaps, handle rotation etc.
  • Easy and elegant ways to detect/get notified of changes to the cash drawer (so you can close/clear your change window when it’s closed, or provide a warning or alarm if it is open too long).
  • Easily and efficiently print to two stations at once (i.e receipt and journal).

Friday, July 17, 2009

Coalesce Follow Up

My earlier post on creating your own Coalesce function only deals with strings, I realised belatedly… here’s a ‘generic’ version that works with other types;

#region Coalesce Overloads

/// <summary>
///
Returns the first value from the collection that does not match the default for the specified type, or else the default for the specified type.
/// </summary>
/// <remarks>
/// <para>
For the set of integers 0, 10, 5, 6 this function will return 10, as it is the first integer in the set that is not 0.</para>
/// <para>
For the set of nullable integers null, 0, 10, 5, 6 this function will return 0, as it is the first integer in the set that is not null.</para>
/// </remarks>
/// <typeparam name="T">
The type of values being compared.</typeparam>
/// <param name="values">
A set of values to find the first non-default value in.</param>
/// <returns>
The first value from the set that is not the default value for the type specified, or else the default for the specified type.</returns>
public static T Coalesce<T>(params T[] values)
{
return Coalesce((IEnumerable<T>)values);
}

/// <summary>
///
Returns the first value from the collection that does not match the default for the specified type, or else the default for the specified type.
/// </summary>
/// <remarks>
/// <para>
For the set of integers 0, 10, 5, 6 this function will return 10, as it is the first integer in the set that is not 0.</para>
/// <para>
For the set of nullable integers null, 0, 10, 5, 6 this function will return 0, as it is the first integer in the set that is not null.</para>
/// </remarks>
/// <typeparam name="T">
The type of values being compared.</typeparam>
/// <param name="values">
A <see cref="System.Collections.IEnumerable"/> set of values to find the first non-default value in.</param>
/// <returns>
The first value from the set that is not the default value for the type specified, or else the default for the specified type.</returns>
public static T Coalesce<T>(IEnumerable<T> values)
{
T defaultValue = default(T);
T retVal = default(T);
foreach (T testValue in values)
{
if (testValue != null && !testValue.Equals(defaultValue))
{
retVal = testValue;
break;
}
}

return retVal;
}

#endregion


Technorati Tags: ,,,

Tuesday, July 14, 2009

Make Multi-Threaded Debugging Easier – Name Your Threads !

Writing multi-threaded code isn’t easy (not if you’re doing it properly), but it is becoming more popular, which means more and more often you’ll find yourself debugging multi-threaded code. Here are some tips for making that easier;

1. Name your threads

Unfortunately this is only a good idea if you are manually starting a thread by creating a System.Threading.Thread object… naming a thread that already has a name causes an error and naming a thread pool thread that will be re-used isn’t a good idea.

The idea behind naming your threads is simple… it makes finding them in the debugger (or your log file) easier. Once you’re in a debug session you an open the ‘Threads’ window using the Debug –> Windows –> Threads. This displays a list of all currently running threads, and you can switch the execution thread to another by double clicking on one. The problem is that if you haven’t named your threads, it’s hard to know which is which.

Visual Studio Thread Window

Also, if you have several threads performing the same operation on different sets of data, you can name each one (with a unique name, like “Processing Record XYZ1234” and record the name in any any log entries you make. This will help when reading the log file, as it will allow you to look at only entries from a single thread, and know what that thread was trying to do and which data it was operating on.

To name a thread, just set the name property before starting it;

System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(this.SleepThread));
t.Name = "My Named Thread";
t.Start();


2. Use Background Threads When Appropriate



Often you need to start a thread that runs in the background and waits for some I/O operation. This often involves calling a ‘blocking’ method, such as Receive on a message queue or serial port object. The problem is you don’t want this thread to keep your application open when the main form is closed, and you don’t want to have to write a whole bunch of code to try and kill the thread.



In this case, just set the IsBackground property of the thread before starting it, like so;



System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(this.SleepThread));
t.Name = "My Background Thread";
t.IsBackground = true;
t.Start();




If you do this, .NET will automatically stop the thread when your application closes.



Finally, if you’re serious about multi-threading you should consider;



1. The TPL library available for .NET, which is included in .NET 4


2.  P-Linq





Technorati Tags: ,,,,,

The Value Of Statistics

This isn’t strictly about .NET, but hey, it’s my blog so here it is anyway. Besides, how many .NET developers use Sql Server ? Quite a few I’d guess, therefore I say it’s relevant.

So a few weeks ago my boss and another colleague of mine were working on some SQL. They had a query that returned the data they wanted but it was running too slowly (about 2 minutes a time). They had been studying it for half an hour with no success when my boss came to see me…

“I don’t expect you can help, I just want to spread the misery I guess.”, he said. He’s a funny guy. So I followed him to the desk where they were working and he explained the query to me.

The query had about 6 or 7 table joins and possibly a sub-select or two, but was otherwise a fairly typical select statement. My boss ran the query returning just count(*) as well as the actual data he wanted, to prove it wasn’t the quantity of data he was getting back , or any expressions in his select clause that was taking the time.

Next he showed me that if he removed a join to one table, the query ran in about 2 seconds. I was about to ask (the obvious question) if the fields he was joining on were indexed when he said; “And that table only has two records in it, it will never have any more than 5. I can’t see how adding an index will help”.

“You want a statistic”, I said with more confidence than I actually felt. I was guessing, albeit it an educated guess.

“How do I do that ? ", he asked

So I walked him through creating a statistic on the column he was joining to in the table with only two rows. You can do this with T-Sql or the Sql Management Studio application which is how we did it… simply navigate to and expand the table in object explorer, then right click on statistics and choose “New Statistics”. From there it should be pretty easy to figure out what to do, it’s similar to creating an index.

So, what happened after we applied the statistic ? Well, my boss sat stunned as his query ran in 2 seconds again but with the offending table join included.

How did the statistic help ? Well the root of the problem was the Sql Server Optimiser (that’s Optimizer if you’re an American) had selected an inefficient method for joining the two tables. Why did it do this ? Because it had no way of knowing how many rows were in the little table, so it guessed, and it guessed badly. Adding the statistic to the table allowed the optimiser to know how many rows existed, and therefore it chose a better solution… this is much better than manually adjusting the join type or adding index hints, as the statistic still allows the optimiser to choose a better plan later if the numbers of rows increases dramatically.

At a Tech Ed session I went to a few years ago they said that if you view a query plan and hover over the joins you’ll see two figures of interest; Estimated Rows and Actual Rows. If these values aren’t within spitting distance of each other (that’s assuming you can’t spit very far) then you’ve either got a problem, or could have a problem... and a statistic of some sort will quite likely help.

Another way to determine if you need statistics is to analyse the query with the Database Tuning Advisor, if you have an edition of Sql Server that includes this. Often when I use this tool it will recommend one or more indexes and several statistics… I always apply the statistics first without the index and retry my queries to see if the performance increase is sufficient before adding indexes.

Why ? Because adding statistics seems (I have only my own anecdotal evidence to stand on here) to add much less overhead to the database than an index. A statistic is basically a count of a  number of records, or records within certain groups of records (i.e. a statistic on an orders table might include counts for rows in each month for which there are orders). This is usually very small data… even over a million records in a table you might add only a few bytes to the size of your database, unlike an index which could add gigabytes if it’s a bad one. Also, statistics don’t seem to add all that much overhead to inserts and updates, and you can choose to have them updated asynchronously or manually (presumably at a scheduled interval) if they do cause you a problem. I’ve never had to do this though, and I’m not sure it’s a good idea unless you really know what you’re doing.

I should note here that we had a similar problem a while back when joining data from an xml block (using xquery inside Sql Server) to a table… the optimizer had no way of knowing the number of rows in the Xml and so it chose bad join plans. Unfortunately in that case we couldn’t create statistics on the xml so instead we had to alter the t-sql to explicitly state the join type (merge, loop etc. not left/right/inner/outer). Once we selected the correct join type for the quantity of data we usually process the statement ran in seconds rather than minutes again.

So, if you’re having a problem with performance joining tables (especially ones of disparate size), or joining some non-table data (like xml) to a table then consider adding statistics or forcing the join type in the sql statement.

 

Monday, July 13, 2009

TimeSpan to English

Ever needed to convert a Time Span into human readable text ? Here’s a nifty little function to do just that.

/// <summary>
///
Returns a string containing the human readable version of this time span, i.e 4 days, 3 hours, 26 minutes and 13.4 seconds.
/// </summary>
/// <param name="timeSpan"></param>
/// <returns></returns>
public static string TimeSpanToText(TimeSpan timeSpan)
{
StringBuilder sb = new StringBuilder(30);

if (timeSpan.Days > 0)
{
sb.Append(timeSpan.Days);
if (timeSpan.Days == 1)
sb.Append(" day");
else
sb.Append(" days");
}

if (timeSpan.Hours > 0)
{
if (sb.Length > 1)
sb.Append(", ");

if (timeSpan.Minutes == 0 && timeSpan.Days > 0)
sb.Append("and ");
sb.Append(timeSpan.Hours);

if (timeSpan.Hours == 1)
sb.Append(" hour");
else
sb.Append(" hours");
}

if (timeSpan.Minutes > 0)
{
if (sb.Length > 0)
sb.Append(", ");
if (timeSpan.Seconds == 0 && timeSpan.Hours > 0)
sb.Append("and ");
sb.Append(timeSpan.Minutes);

if (timeSpan.Minutes == 1)
sb.Append(" minute");
else
sb.Append(" minutes");
}

if (timeSpan.Seconds > 0)
{
if (sb.Length > 0)
sb.Append(", ");

if (timeSpan.Minutes > 0)
sb.Append("and ");
sb.Append(timeSpan.Seconds);
if (timeSpan.Milliseconds > 0)
{
sb.Append(".");
sb.Append(timeSpan.Milliseconds);
}

if (timeSpan.Seconds == 1 && timeSpan.Milliseconds == 0)
sb.Append(" second");
else
sb.Append(" seconds");
}

if (timeSpan.Milliseconds > 0 && timeSpan.Seconds == 0)
{
sb.Append(timeSpan.Milliseconds);
if (timeSpan.Milliseconds == 1)
sb.Append(" millisecond");
else
sb.Append(" milliseconds");

sb.Append(" (");
sb.Append(timeSpan.Ticks);
sb.Append(" ticks)");
}

return sb.ToString();
}



A Tidier Way To Parse Enum Values

Here are some methods I wrote for parsing strings into their enum equivalents. I work in .NET 2.0 mostly so I just have these as static methods on a static object, but they could easily be turned into extension methods for the enum class, which would probably make them easier to access and reduce typing.

While converting a string to it’s enum equivalent isn’t hard, this hides all the nasty casting etc.

        #region ParseEnumValue Overloads

/// <summary>
///
Parses the string provided back into it's equivalent enum value.
/// </summary>
/// <remarks>
///
This overload is case-sensitive.
/// </remarks>
/// <typeparam name="T">
The type of enum to convert the string to.</typeparam>
/// <param name="enumValue">
A string containing the name of a value from the specified enum.</param>
/// <returns>
A the value from the enum specified that matches the specified string.</returns>
/// <exception cref="System.ArgumentException">
Occurs if the string does not match a value from the enum.</exception>
/// <exception cref="System.ArgumentNullException">
Occurs if the string provided is null.</exception>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
public static T ParseEnumValue<T>(string enumValue)
{
return ParseEnumValue<T>(enumValue, false);
}

/// <summary>
///
Parses the string provided back into it's equivalent enum value.
/// </summary>
/// <typeparam name="T">
The type of enum to convert the string to.</typeparam>
/// <param name="enumValue">
A string containing the name of a value from the specified enum.</param>
/// <param name="ignoreCase">
A boolean indicating whether or not the conversion should succeed if the string matches an enum but with a different case.</param>
/// <returns>
A the value from the enum specified that matches the specified string.</returns>
/// <exception cref="System.ArgumentException">
Occurs if the string does not match a value from the enum.</exception>
/// <exception cref="System.ArgumentNullException">
Occurs if the string provided is null.</exception>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")]
public static T ParseEnumValue<T>(string enumValue, bool ignoreCase)
{
if (enumValue == null) throw new ArgumentNullException("enumValue");

return (T)System.Enum.Parse(typeof(T), enumValue, ignoreCase);
}

#endregion

#region
TryParseEnumValue Overloads

/// <summary>
///
Attempts to parse the specified enum.
/// </summary>
/// <typeparam name="T">
The type of enum to convert the string to.</typeparam>
/// <param name="s">
A string containing the name of a value from the specified enum.</param>
/// <param name="value">
Returns either the converted value, or the default value for the enum.</param>
/// <returns>
A boolean indicating whether or not the conversion was successful.</returns>
/// <exception cref="System.ArgumentNullException">
Occurs if the string provided is null.</exception>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s")]
public static bool TryParseEnumValue<T>(string s, out T value)
{
return TryParseEnumValue<T>(s, out value, false);
}

/// <summary>
///
Attempts to parse the specified enum.
/// </summary>
/// <typeparam name="T">
The type of enum to convert the string to.</typeparam>
/// <param name="s">
A string containing the name of a value from the specified enum.</param>
/// <param name="value">
Returns either the converted value, or the default value for the enum.</param>
/// <param name="ignoreCase">
A boolean indicating whether or not the conversion should succeed if the string matches an enum but with a different case.</param>
/// <returns>
A boolean indicating whether or not the conversion was successful.</returns>
/// <exception cref="System.ArgumentNullException">
Occurs if the string provided is null.</exception>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "s"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#")]
public static bool TryParseEnumValue<T>(string s, out T value, bool ignoreCase)
{
bool retVal = false;
#if !CEBUILD
if (s == null) throw new ArgumentNullException("s");

value = default(T);
if (IsEnumValue(typeof(T), s, ignoreCase))
{
retVal = true;
value = (T)System.Enum.Parse(typeof(T), s, ignoreCase);
}
#else
try
{
value = (T)System.Enum.Parse(typeof(T), s, ignoreCase);
retVal = true;
}
catch (FormatException)
{
value = default(T);
retVal = false;
}
#endif
return
retVal;
}

#endregion




Technorati Tags: ,,,,,

A C# Coalesce Function

The Coalesce function in t-sql is quite useful, it takes a list of arguments and returns the first non-null value. Here’s a C# version, which occasionally comes in handy. Note there are four overloads to make it easy to use regardless of how you need to pass your arguments;

#region Coalesce Overloads

/// <summary>
///
Returns the first non-null value from the enumerable set of string values provided.
/// </summary>
/// <param name="values">
An enumerable set of string values.</param>
/// <returns>
The first non-null string found in the enumerable set of values provided, or null if no non-null value was found.</returns>
public static string Coalesce(IEnumerable<string> values)
{
return Coalesce(false, values);
}

/// <summary>
///
Returns the first non-null (and non-empty string value if the nullOrEmpty parameter is true) value from the enumerable set of string values provided.
/// </summary>
/// <param name="nullOrEmpty">
Determines whether an empty string is treated in the same way as a null string.</param>
/// <param name="values">
An enumerable set of string values.</param>
/// <returns>
The first non-null (and non-empty string value if the nullOrEmpty parameter is true) string found in the enumerable set of values provided, or null if no non-null value was found.</returns>
public static string Coalesce(bool nullOrEmpty, IEnumerable<string> values)
{
string retVal = null;

using (IEnumerator<string> enumerator = values.GetEnumerator())
{
while (retVal == null || (nullOrEmpty == true && retVal.Length <= 0))
{
retVal = enumerator.Current;
if (!enumerator.MoveNext())
break;
}
}

return retVal;
}

/// <summary>
///
Returns the first non-null value from the enumerable set of string values provided.
/// </summary>
/// <param name="listValues">
A list of string values to search.</param>
/// <returns>
The first non-null string found in the enumerable set of values provided, or null if no non-null value was found.</returns>
public static string Coalesce(params string[] listValues)
{
return Coalesce(false, listValues);
}

/// <summary>
///
Returns the first non-null (and non-empty string value if the nullOrEmpty parameter is true) value from the list of string values provided.
/// </summary>
/// <param name="nullOrEmpty">
Determines whether an empty string is treated in the same way as a null string.</param>
/// <param name="listValues">
An list of string values.</param>
/// <returns>
The first non-null (and non-empty string value if the nullOrEmpty parameter is true) string found in the list of values provided, or null if no non-null value was found.</returns>
public static string Coalesce(bool nullOrEmpty, params string[] listValues)
{
return Coalesce(nullOrEmpty, listValues);
}

#endregion



Technorati Tags: ,,,