Month: November 2016

Object Extensions

Posted on Updated on

Here is my class of object extensions I use.

using System;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace Dahl.Core.Extensions
{
    public static partial class Extensions
    {
        public static string AsString( this object source ) { return source as string; }
        public static DateTime AsDateTime( this object source ) { return (DateTime)source; }
        public static short AsShort( this object source ) { return (short)source; }
        public static int   AsInt( this object source ) { return (int)source; }
        public static long  AsLong( this object source ) { return (long)source; }
        public static bool  AsBool( this object source ) { return (bool)source; }
        public static byte  AsByte( this object source ) { return (byte)source; }

        public static DateTime? AsNullableDateTime( this object source ) { return source as DateTime?; }
        public static short?    AsNullableShort( this object source ) { return source as short?; }
        public static int?      AsNullableInt( this object source ) { return source as int?; }
        public static long?     AsNullableLong( this object source ) { return source as long?; }
        public static bool?     AsNullableBool( this object source ) { return source as bool?; }
        public static byte?     AsNullableByte( this object source ) { return (byte?)source; }

        public static DateTime? AsDateTimeNullable( this object source ) { return source as DateTime?; }
        public static short? AsShortNullable( this object source )       { return source as short?; }
        public static int?   AsIntNullable( this object source )         { return source as int?; }
        public static long?  AsLongNullable( this object source )        { return source as long?; }
        public static bool?  AsBoolNullable( this object source )        { return source as bool?; }
        public static byte?  AsByteNullable( this object source )        { return (byte?)source; }

        public static byte AsTinyInt( this object source )               { return (byte)source; }
        public static byte? AsTinyIntNullable( this object source )       { return (byte?)source; }

        public static short AsSmallInt( this object source ) { return (short)source; }
        public static short? AsSmallIntNullable( this object source ) { return (short?)source; } 

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// Copy properties from source object into destination object.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="src">copy data from this object into the specified dst object</param>
        /// <param name="dst">copy data into this object</param>
        public static void CopyFrom<T>( this T dst, T src )
        {
            PropertyInfo[] srcProperties = src.GetType().GetProperties( BindingFlags.Public | BindingFlags.Instance );
            foreach ( PropertyInfo srcProperty in srcProperties )
            {
                if ( srcProperty.CanRead && srcProperty.CanWrite )
                {
                    PropertyInfo dstProperty = dst.GetType().GetProperty( srcProperty.Name );
                    if ( dstProperty != null )
                    {
                        object val = srcProperty.GetValue( src, null );
                        dstProperty.SetValue( dst, val, null );
                    }
                }
            }
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// Makes a new object and copies 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="S"></param>
        /// <returns></returns>
        public static T GetCopy<T>( this T S )
        {
            T newObj = Activator.CreateInstance<T>();
            foreach ( PropertyInfo i in newObj.GetType().GetProperties() )
            {
                //"EntitySet" is specific to link and this conditional logic is optional/can be ignored
                if ( i.CanWrite && i.PropertyType.Name.Contains( "EntitySet" ) == false )
                {
                    object value = S.GetType().GetProperty( i.Name ).GetValue( S, null );
                    i.SetValue( newObj, value, null );
                }
            }

            return newObj;
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// Perform a deep Copy of an object, object must be serializable.
        /// </summary>
        /// <typeparam name="T">The type of object being copied.</typeparam>
        /// <param name="source">The object instance to copy.</param>
        /// <returns>The copied object.</returns>
        public static T Clone<T>( this T source )
        {
            if ( !typeof( T ).IsSerializable )
            {
                throw new ArgumentException( "The type must be serializable.", nameof( source ) );
            }

            // Don't serialize a null object, simply return the default for that object
            if ( object.ReferenceEquals( source, null ) )
            {
                return default( T );
            }

            IFormatter formatter = new BinaryFormatter();
            Stream stream = new MemoryStream();
            using ( stream )
            {
                formatter.Serialize( stream, source );
                stream.Seek( 0, SeekOrigin.Begin );
                return (T)formatter.Deserialize( stream );
            }
        }
    }
}

Linq Extensions

Posted on Updated on

Here is my class of linq extensions I use.

This is an example of using the extension in a unit test.

[TestMethod]
public void Linq_OrderBy()
{
    List<User> userList = UserList.OrderBy( "FirstName"  ).ToList();
    Trace.WriteLine( "===  Order By FirstName ascending ===" );
    foreach ( User user in userList )
        Trace.WriteLine( $"FirstName: {user.FirstName},  LastName: {user.LastName}" );

    userList = UserList.OrderBy( "LastName", false ).ToList();
    Trace.WriteLine( "===  Order By LastName descending ====" );
    foreach ( User user in userList )
        Trace.WriteLine( $"FirstName: {user.FirstName},  LastName: {user.LastName}" );

}

private static readonly List<User> UserList = new List<User>() {
    new User { FirstName = "firstName03", LastName= "lastName08" },
    new User { FirstName = "firstName07", LastName= "lastName04" },
    new User { FirstName = "firstName06", LastName= "lastName05" },
    new User { FirstName = "firstName04", LastName= "lastName07" },
    new User { FirstName = "firstName10", LastName= "lastName01" },
    new User { FirstName = "firstName09", LastName= "lastName02" },
    new User { FirstName = "firstName08", LastName= "lastName03" },
    new User { FirstName = "firstName05", LastName= "lastName06" },
    new User { FirstName = "firstName02", LastName= "lastName09" },
    new User { FirstName = "firstName01", LastName= "lastName10" }
};
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Dahl.Core.Extensions
{
    public static partial class Extensions
    {
        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// Sorts the elements of a sequence according to a key. 
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="source"></param>
        /// <param name="keySelector"></param>
        /// <param name="descending"></param>
        /// <returns></returns>
        public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>( this IEnumerable<TSource> source,
                                                                          Func<TSource, TKey> keySelector,
                                                                          bool descending )
        {
            if ( descending )
                return source.OrderByDescending( keySelector );

            return source.OrderBy( keySelector );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="source"></param>
        /// <param name="keySelector"></param>
        /// <param name="descending"></param>
        /// <returns></returns>
        public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>( this IQueryable<TSource> source,
                                                                         Expression<Func<TSource, TKey>> keySelector,
                                                                         bool descending )
        {
            return descending ? source.OrderByDescending( keySelector )
                              : source.OrderBy( keySelector );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="sortExpression"></param>
        /// <param name="sortAscending"></param>
        /// <returns></returns>
        public static IQueryable<T> OrderBy<T>( this IQueryable<T> list, string sortExpression, bool sortAscending = true )
        {
            return sortAscending ? list.OrderBy( f => OrderFunc( f, sortExpression ) )
                                 : list.OrderByDescending( f => OrderFunc( f, sortExpression ) );
        }


        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="sortExpression"></param>
        /// <param name="sortAscending"></param>
        /// <returns></returns>
        public static IEnumerable<T> OrderBy<T>( this IEnumerable<T> list, string sortExpression, bool sortAscending = true )
        {
            return sortAscending ? list.OrderBy( f => OrderFunc( f, sortExpression ) )
                                 : list.OrderByDescending( f => OrderFunc( f, sortExpression ) );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public static object GetChildObject<T>( T obj, string propertyName )
        {
            Type t = obj.GetType();
            PropertyInfo prop = t.GetProperty( propertyName );
            if ( prop == null )
            {
                string msg = $"PropertyName \"{propertyName}\" is not defined in class \"{obj.GetType().FullName}\".";
                throw new ArgumentException( msg );
            }

            return prop.GetValue( obj, null ) ?? Activator.CreateInstance( prop.PropertyType );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        private static object OrderFunc<T>( T obj, string propertyName )
        {
            string propName = propertyName;
            object newObj = obj;

            if ( propertyName.Contains( '.' ) )
            {   // the requested property is contained in a child object
                string[] parts = propertyName.Split( '.' );
                int numParts = parts.Length - 1;
                for ( int i = 0; i < numParts; i++ )
                    newObj = GetChildObject( newObj, parts[i] );

                propName = parts[numParts];
            }

            PropertyInfo propertyGetter = newObj.GetType()
                                                .GetProperty( propName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase );
            if ( propertyGetter == null )
            {
                string msg = @"Sort Expression could not find property name provided<br />" + $"PropertyName: {propertyName}";
                throw new ArgumentException( msg );
            }

            return propertyGetter.GetValue( newObj, null );
        }

        //-----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TSrc"></typeparam>
        /// <typeparam name="TKey"></typeparam>
        /// <param name="src"></param>
        /// <param name="selector"></param>
        /// <returns></returns>
        public static IEnumerable<TSrc> DistinctBy<TSrc, TKey>( this IEnumerable<TSrc> src, Func<TSrc, TKey> selector )
        {
            HashSet<TKey> keys = new HashSet<TKey>();
            return src.Where( element => keys.Add( selector( element ) ) );
        }
    }
}

String Extensions

Posted on Updated on

Here is my class of string extensions I like to use. It allows me to write code that is easier for me to read. For me, I find the following two examples a lot easier to read and allows me to be more consistent in writing code.

// Test if two string are not equal
string s1 = "this is string #1";
string s2 = "this is string #2";

if ( s1.IsNotEqualIgnoreCase( s2 ) )
    DoSomething();
// convert a string to an integer
string s = "12356";
int x = s.ToInt();

C# class Extensions:

using System;
using System.Globalization;
using System.Text.RegularExpressions;

namespace Dahl.Core.Extensions
{
    public static class StringExt
    {
        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Trims whitespace from the string.
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string TrimWhiteSpace( this string source )
        {
            if ( string.IsNullOrEmpty( source ) )
                return string.Empty;

            return source.Trim();
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Determines whether two T:string objects have the same value ignoring case,
        /// uses StringComparison.OrdinalIgnoreCase 
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <param name="val">the value to compare</param>
        /// <returns></returns>
        public static bool IsEqualIgnoreCase( this string source, string val )
        {
            if ( string.IsNullOrEmpty( source ) && string.IsNullOrEmpty( val ) )
                return false;

            if ( string.IsNullOrEmpty( source ) )
                return false;

            return string.Equals( source, val, StringComparison.OrdinalIgnoreCase );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Determines whether 2 specified T:String objects have the same value ignoring case,
        /// uses StringComparison.OrdinalIgnoreCase 
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <param name="val">the value to compare</param>
        /// <returns></returns>
        public static bool IsNotEqual( this string source, string val )
        {
            if ( string.IsNullOrEmpty( source ) && !string.IsNullOrEmpty( val ) )
                return true;

            if ( string.IsNullOrEmpty( val ) )
                return true;

            return !string.Equals( source, val );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Determines whether 2 specified T:String objects have the same value ignoring case,
        /// uses StringComparison.OrdinalIgnoreCase 
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <param name="val">the value to compare</param>
        /// <returns></returns>
        public static bool IsNotEqualIgnoreCase( this string source, string val )
        {
            if ( string.IsNullOrEmpty( source ) && !string.IsNullOrEmpty( val ) )
                return true;

            if ( string.IsNullOrEmpty( val ) )
                return true;

            return !string.Equals( source, val, StringComparison.OrdinalIgnoreCase );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Returns a value indicating whether the specified String object occurs within this string ignoring case,
        /// uses StringComparison.OrdinalIgnoreCase 
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <param name="val">the value to find</param>
        /// <returns></returns>
        public static bool ContainsIgnoreCase( this string source, string val )
        {
            if ( string.IsNullOrEmpty( source ) || string.IsNullOrEmpty( val ) )
                return false;

            return source.IndexOf( val, StringComparison.OrdinalIgnoreCase ) >= 0;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Returns a value indicating whether the specified String object contains anything
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <returns></returns>
        public static bool IsNullOrEmpty( this string source )
        {
            return string.IsNullOrEmpty( source );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Returns a value indicating whether the specified String object contains anything
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <returns></returns>
        public static bool IsNotNullOrEmpty( this string source )
        {
            return !string.IsNullOrEmpty( source );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Determines whether the beginning of this string instance matches the specified string ignoring case,
        /// uses StringComparison.OrdinalIgnoreCase 
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <param name="val">the value to find</param>
        /// <returns></returns>
        public static bool StartsWithIgnoreCase( this string source, string val )
        {
            if ( string.IsNullOrEmpty( source ) || string.IsNullOrEmpty( val ) )
                return false;

            return source.StartsWith( val, StringComparison.OrdinalIgnoreCase );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Determines whether the end of this string instance matches the specified string ignoring case,
        /// uses StringComparison.OrdinalIgnoreCase 
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <param name="val">the value to find</param>
        /// <returns></returns>
        public static bool EndsWithIgnoreCase( this string source, string val )
        {
            if ( string.IsNullOrEmpty( source ) || string.IsNullOrEmpty( val ) )
                return false;

            return source.EndsWith( val, StringComparison.OrdinalIgnoreCase );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Replaces the old value with the specified new value ignoring case.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="oldValue">The part of the string to be replaced by the newValue</param>
        /// <param name="newValue">The new string to replace the old value</param>
        /// <returns></returns>
        public static string ReplaceIgnoreCase( this string source, string oldValue, string newValue )
        {
            string s;
            try
            {
                if ( source == null )
                    source = string.Empty;

                if ( oldValue == null )
                    oldValue = string.Empty;

                s = Regex.Replace( source, oldValue, newValue, RegexOptions.IgnoreCase );
            }
            catch ( Exception )
            {
                s = oldValue;
            }

            return s;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ToString( this string source )
        {
            if ( source == null )
                return string.Empty;

            return source.ToString( CultureInfo.InvariantCulture );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Returns a string up to the maxLen specified.
        /// </summary>
        /// <param name="source"></param>
        /// <param name="maxLen">The maximum length of the sting</param>
        /// <returns></returns>
        public static string ToString( this string source, int maxLen )
        {
            if ( string.IsNullOrEmpty( source ) )
                return string.Empty;

            if ( source.Length > maxLen )
                return source.Substring( 0, maxLen );

            return source.TrimEnd();
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Takes a string and if its length is greater than maxLen it trims it to maxLen-3 and 
        /// appends three periods to the string.
        /// </summary>
        /// <param name="source">the string to compare</param>
        /// <param name="maxLen">maximum length of string to return</param>
        /// <returns></returns>
        public static string ToEllipsis( this string source, int maxLen )
        {
            if ( string.IsNullOrEmpty( source ) )
                return string.Empty;

            maxLen -= 3;
            if ( source.Length > maxLen )
                return string.Format( "{0}...", source.Substring( 0, maxLen ) );

            return source.TrimEnd();
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// If possible makes a Guid from the string provided, otherwise it returns an Empty Guid.
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static Guid ToGuid( this string source )
        {
            Guid result;
            try
            {
                result = new Guid( source );
            }
            catch ( Exception )
            {
                result = Guid.Empty;
            }

            return result;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Converts string to title case by first changing all characters to lower case.
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static string ToTitleCase( this string source )
        {
            CultureInfo cultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture;
            return cultureInfo.TextInfo.ToTitleCase( source.ToLower() );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Convert string to DateTime, if null or empty then returns defaultValue
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static DateTime ToDateTime( this string source, DateTime defaultValue = default( DateTime ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            DateTime result;
            if ( !DateTime.TryParse( source, out result ) )
                result = defaultValue;

            return result;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Convert string to DateTime, if null or empty then returns defaultValue
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static DateTime ToDate( this string source, DateTime defaultValue = default( DateTime ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            DateTime result;
            if ( !DateTime.TryParse( source, out result ) )
                result = defaultValue;

            return new DateTime( result.Year, result.Month, result.Day );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Converts string into a boolean value.
        /// </summary>
        /// <param name="source">Valid values are "f" or "false" and "t" or "true"</param>
        /// <param name="defaultValue">If parameter is not specified, false is returned.</param>
        /// <returns></returns>
        public static bool ToBool( this string source, bool defaultValue = default( bool ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            string s = source.ToLower().Trim();
            if ( s.Equals( "false" ) || s.Equals( "f" ) || s == "0" )
                return false;

            if ( s.Equals( "true" ) || s.Equals( "t" ) || s == "1" )
                return true;

            return defaultValue;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Convert string to short, if null or empty then returns defaultValue
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static short ToShort( this string source, short defaultValue = default( short ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            short result;
            source = source.Replace( ",", "" );
            if ( short.TryParse( source, out result ) )
                return result;

            return defaultValue;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Convert string to Int, if null or empty then returns defaultValue
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static int ToInt( this string source, int defaultValue = default( int ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            int result;
            source = source.Replace( ",", "" );
            if ( int.TryParse( source, out result ) )
                return result;

            return defaultValue;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Trys to converts an object to an integer
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static int ToInt( this object source, int defaultValue = default( int ) )
        {
            int target = defaultValue;
            if ( source is string )
                target = IntParse( source.ToString() );
            else if ( source is int )
                target = (int)source;

            return target;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Converts a string to an integer 
        /// </summary>
        /// <param name="source">The string to parse</param>
        /// <param name="defaultValue">If provided, a value to return if the string cannot be parsed, 
        ///                   if not provided zero will be used as the default value</param>
        /// <returns>The parsed value if string represents a legal integer, otherwise the default value</returns>
        public static int IntParse( this string source, int defaultValue = default( int ) )
        {
            int target;
            int.TryParse( source, out target );
            return target;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Convert string to long, if null or empty then returns defaultValue
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static long ToLong( this string source, long defaultValue = default( long ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            long result;
            source = source.Replace( ",", "" );
            if ( long.TryParse( source, out result ) )
                return result;

            return defaultValue;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Convert string to double, if null or empty then returns defaultValue
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static double ToDouble( this string source, double defaultValue = default( double ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            double result;
            source = source.Replace( ",", "" );
            if ( double.TryParse( source, out result ) )
                return result;

            return defaultValue;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Convert string to float, if null or empty then returns defaultValue
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static float ToFloat( this string source, float defaultValue = default( float ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            float result;
            source = source.Replace( ",", "" );
            if ( float.TryParse( source, out result ) )
                return result;

            return defaultValue;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Converts string to decimal, if null or empty then uses default value
        /// </summary>
        /// <param name="source"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static decimal ToDecimal( this string source, decimal defaultValue = default( decimal ) )
        {
            if ( string.IsNullOrEmpty( source ) )
                return defaultValue;

            decimal result;
            source = source.Replace( ",", "" );
            if ( decimal.TryParse( source, out result ) )
                return result;

            return defaultValue;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// 
        /// </summary>
        private static readonly Regex NonDigit = new Regex( "\\D" );

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Returns only Digits
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        public static string OnlyDigits( this string number )
        {
            return NonDigit.Replace( number, string.Empty );
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Returns a short date string
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static string ToShortDateString( this DateTime? date )
        {
            return date?.ToShortDateString() ?? string.Empty;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Returns a long date string
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static string ToLongDateString( this DateTime? date )
        {
            return date?.ToLongDateString() ?? string.Empty;
        }

        ///----------------------------------------------------------------------------------------
        /// <summary>
        /// Provide a string to test pattern to see if email address is probably in a valid format.
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public static bool IsValidEmailFormat( this string source )
        {
            const string pattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$";
            return Regex.IsMatch( source, pattern );
        }
    }
}