Friday, October 25, 2013

C# : Safely get the Checked() of a Control across threads


        public static Boolean Checked( [CanBeNull] this CheckBox control ) {
            if ( null == control ) {
                return false;
            }
            return control.InvokeRequired ? ( Boolean )control.Invoke( new Func<Boolean>( () => control.Checked ) ) : control.Checked;
        }

C# : Safely get the Text() of a Control across threads.


        /// <summary>
        ///     Safely get the <see cref="Control.Text"/>() of a <see cref="Control"/> across threads.
        /// </summary>
        /// <param name="control"></param>
        /// <returns></returns>
        public static String Text( [CanBeNull] this Control control ) {
            if ( null == control ) {
                return String.Empty;
            }
            return control.InvokeRequired ? control.Invoke( new Func<string>( () => control.Text ) ) as String ?? String.Empty : control.Text;
        }

Monday, October 21, 2013

C#: USD Wallet - Denominations


#region License
// This notice must be kept visible in the source.
// This section of source code belongs to Protiguous@Protiguous.Info.
// Royalties must be paid via bitcoin @ 1PRoT78h5EuPgWECtgFYeVRhUb2tQXskXL
// Usage of the source code or compiled binaries is AS-IS.
// "AI/IDenomination.cs" was last cleaned on 2013/10/21
#endregion
 
namespace AI.Measurement.Currency.USD {
    using System;
    using Annotations;
 
    public interface IDenomination {
        Decimal FaceValue { get; }
 
        [UsedImplicitly]
        String Formatted { get; }
    }
 
    /// <summary>
    /// </summary>
    /// <see cref="http://www.treasury.gov/resource-center/faqs/Currency/Pages/denominations.aspx" />
    /// <see cref="http://en.wikipedia.org/wiki/Banknote" />
    public interface IBankNote : IDenomination { }
 
    /// <summary>
    /// </summary>
    /// <see cref="http://www.treasury.gov/resource-center/faqs/Currency/Pages/denominations.aspx" />
    /// <see cref="http://en.wikipedia.org/wiki/Coin" />
    public interface ICoin : IDenomination { }
 
    namespace Denominations {
        using System.Diagnostics;
 
        [DebuggerDisplay( "{Formatted,nq}" )]
        [UsedImplicitly]
        public sealed class Dime : ICoin {
            public Decimal FaceValue { get { return 0.10M; } }
            public String Formatted { get { return String.Format( "{0:C}", this.FaceValue ); } }
        }
 
        [DebuggerDisplay( "{Formatted,nq}" )]
        [UsedImplicitly]
        public sealed class Fifty : IBankNote {
            public Decimal FaceValue { get { return 50.00M; } }
            public String Formatted { get { return String.Format( "{0:C}", this.FaceValue ); } }
        }
 
        [DebuggerDisplay( "{Formatted,nq}" )]
        [UsedImplicitly]
        public sealed class Five : IBankNote {
            public Decimal FaceValue { get { return 5.00M; } }
            public String Formatted { get { return String.Format( "{0:C}", this.FaceValue ); } }
        }
 
        [DebuggerDisplay( "{Formatted,nq}" )]
        [UsedImplicitly]
        public sealed class Hundred : IBankNote {
            public Decimal FaceValue { get { return 100.00M; } }
            public String Formatted { get { return String.Format( "{0:C}", this.FaceValue ); } }
        }
 
        [DebuggerDisplay( "{Formatted,nq}" )]
        [UsedImplicitly]
        public sealed class Nickel : ICoin {
            public Decimal FaceValue { get { return 0.05M; } }
            public String Formatted { get { return String.Format( "{0:C}", this.FaceValue ); } }
        }
 
        [DebuggerDisplay( "{Formatted,nq}" )]
        [UsedImplicitly]
        public class One : IBankNote {
            public Decimal FaceValue { get { return 1.00M; } }
            public String Formatted { get { return String.Format( "{0:C}", this.FaceValue ); } }
        }
 
        [DebuggerDisplay( "{Formatted,nq}" )]
        [UsedImplicitly]
        public sealed class Penny : ICoin {
            public Decimal FaceValue { get { return 0.01M; } }
            public String Formatted { get { return String.Format( "{0:C}", this.FaceValue ); } }
        }
 
        [DebuggerDisplay( "{Formatted,nq}" )]
        [UsedImplicitly]
        public sealed class Quarter : ICoin {
            public Decimal FaceValue { get { return 0.25M; } }
            public String Formatted { get { return String.Format( "{0:C}", this.FaceValue ); } }
        }
 
        [DebuggerDisplay( "{Formatted,nq}" )]
        [UsedImplicitly]
        public class Ten : IBankNote {
            public Decimal FaceValue { get { return 10.00M; } }
            public String Formatted { get { return String.Format( "{0:C}", this.FaceValue ); } }
        }
 
        [DebuggerDisplay( "{Formatted,nq}" )]
        [UsedImplicitly]
        public class Twenty : IBankNote {
            public Decimal FaceValue { get { return 20.00M; } }
            public String Formatted { get { return String.Format( "{0:C}", this.FaceValue ); } }
        }
 
        /* This bill exists, but it is so rarely found and therefore not calculated.
        [DebuggerDisplay( "{Formatted,nq}" )]
        [UsedImplicitly]
        public class Two : IPaperBill {
            public Decimal FaceValue { get { return 2.00M; } }
            public String Formatted { get { return String.Format( "{0:C}", this.FaceValue ); } }
        }
         * */
    }
}

C#: USD Wallet - Main Class


#region License
// This notice must be kept visible in the source.
// This section of source code belongs to Protiguous@Protiguous.Info.
// Royalties must be paid via bitcoin @ 1PRoT78h5EuPgWECtgFYeVRhUb2tQXskXL
// Usage of the source code or compiled binaries is AS-IS.
// "AI/Wallet.cs" was last cleaned on 2013/10/21.
#endregion
 
namespace AI.Measurement.Currency.USD {
    using System;
    using System.Collections;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.Threading.Tasks.Dataflow;
    using Annotations;
    using Maths;
    using NUnit.Framework;
    using Threading;
 
    /// <summary>
    ///     My first go at a thread-safe Wallet class for US dollars and coins.
    ///     It's more pseudocode for learning than for production..
    ///     Use at your own risk, as its thoroughly untested. :) 
    ///     Any tips or ideas? Any dos or dont's? Email me!
    /// </summary>
    [DataContract( IsReference = true )]
    [DebuggerDisplay( "{Formatted,nq}" )]
    public class Wallet : IEnumerable<KeyValuePair<IDenomination, UInt64>> {
 
        [DataMember]
        [NotNull]
        public readonly Statistics Statistics = new Statistics();
 
        /// <summary>
        ///     Count of each <see cref="IBankNote" />.
        /// </summary>
        [NotNull]
        private readonly ConcurrentDictionary<IBankNote, UInt64> _bankNotes = new ConcurrentDictionary<IBankNote, UInt64>();
 
        /// <summary>
        ///     Count of each <see cref="ICoin" />.
        /// </summary>
        [NotNull]
        private readonly ConcurrentDictionary<ICoin, UInt64> _coins = new ConcurrentDictionary<ICoin, UInt64>();
 
        public IEnumerable<KeyValuePair<ICoin, UInt64>> CoinsGrouped {
            [NotNull]
            get {
                Assert.NotNull( this._coins );
                return this._coins;
            }
        }
 
        [UsedImplicitly]
        public String Formatted {
            get {
                var total = this.Total.ToString( "C4" );
                Assert.NotNull( this._bankNotes );
                var notes = this._bankNotes.Aggregate( 0UL, ( current, pair ) => current + pair.Value );
 
                Assert.NotNull( this._coins );
                var coins = this._coins.Aggregate( 0UL, ( current, pair ) => current + pair.Value );
                return String.Format( "{0} in {1:N0} notes and {2:N0} coins.", total, notes, coins );
            }
        }
 
        /// <summary>
        ///     Return an expanded list of the <see cref="Notes" /> and <see cref="Coins" /> in this <see cref="Wallet" />.
        /// </summary>
        public IEnumerable<IDenomination> NotesAndCoins {
            [NotNull]
            get { return this.Coins.Concat<IDenomination>( this.Notes ); }
        }
 
        public IEnumerable<KeyValuePair<IBankNote, UInt64>> NotesGrouped {
            [NotNull]
            get { return this._bankNotes; }
        }
 
        /// <summary>
        ///     Return each <see cref="ICoin" /> in this <see cref="Wallet" />.
        /// </summary>
        public IEnumerable<ICoin> Coins {
            [NotNull]
            get { return this._coins.SelectMany( pair => 1.To( pair.Value ), ( pair, valuePair ) => pair.Key ); }
        }
 
        /// <summary>
        ///     Return the count of each type of <see cref="Notes" /> and <see cref="Coins" />.
        /// </summary>
        public IEnumerable<KeyValuePair<IDenomination, UInt64>> Groups {
            [NotNull]
            get {
                return this._bankNotes.Cast<KeyValuePair<IDenomination, ulong>>()
                           .Concat( this._coins.Cast<KeyValuePair<IDenomination, ulong>>() );
            }
        }
 
        public Guid ID { get; private set; }
 
        /// <summary>
        ///     Return each <see cref="IBankNote" /> in this <see cref="Wallet" />.
        /// </summary>
        public IEnumerable<IBankNote> Notes { get { return this._bankNotes.SelectMany( pair => 1.To( pair.Value ), ( pair, valuePair ) => pair.Key ); } }
 
        /// <summary>
        ///     Return the total amount of money contained in this <see cref="Wallet" />.
        /// </summary>
        public Decimal Total {
            get {
                var total = this._coins.Aggregate( Decimal.Zero, ( current, pair ) => current + pair.Key.FaceValue * pair.Value );
                total += this._bankNotes.Aggregate( Decimal.Zero, ( current, pair ) => current + pair.Key.FaceValue * pair.Value );
                return total;
            }
        }
 
        private ActionBlock<TransactionMessage> Actor { get; set; }
 
        private Wallet( Guid id ) {
            this.ID = id;
            this.Statistics.Reset();
            this.Actor = new ActionBlock<TransactionMessage>( message => {
                switch ( message.TransactionType ) {
                    case TransactionType.Deposit:
                        Extensions.Deposit( this, message );
                        break;
                    case TransactionType.Withdraw:
                        this.TryWithdraw( message );
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }, Blocks.ManyProducers.ConsumeSerial );
        }
 
        private Boolean TryWithdraw( TransactionMessage message ) {
            var asBankNote = message.Denomination as IBankNote;
            if ( null != asBankNote ) {
                return this.TryWithdraw( asBankNote, message.Quantity );
            }
 
            var asCoin = message.Denomination as ICoin;
            if ( null != asCoin ) {
                return this.TryWithdraw( asCoin, message.Quantity );
            }
 
            throw new NotImplementedException( String.Format( "Unknown denomination {0}", message.Denomination ) );
        }
 
        /// <summary>
        ///     Attempt to <see cref="TryWithdraw(IBankNote,ulong)" /> one or more <see cref="IBankNote" /> from this
        ///     <see cref="Wallet" />.
        /// </summary>
        /// <param name="bankNote"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <remarks>Locks the wallet.</remarks>
        public Boolean TryWithdraw( [CanBeNull] IBankNote bankNote, UInt64 quantity ) {
            if ( bankNote == null ) {
                return false;
            }
            if ( quantity <= 0 ) {
                return false;
            }
            lock ( this._bankNotes ) {
                if ( !this._bankNotes.ContainsKey( bankNote ) || this._bankNotes[ bankNote ] < quantity ) {
                    return false; //no bills to withdraw!
                }
                this._bankNotes[ bankNote ] -= quantity;
                return true;
            }
        }
 
        /// <summary>
        ///     Attempt to <see cref="TryWithdraw(ICoin,ulong)" /> one or more <see cref="ICoin" /> from this <see cref="Wallet" />
        ///     .
        /// </summary>
        /// <param name="coin"></param>
        /// <param name="quantity"></param>
        /// <returns></returns>
        /// <remarks>Locks the wallet.</remarks>
        public Boolean TryWithdraw( [NotNull] ICoin coin, UInt64 quantity ) {
            if ( coin == null ) {
                throw new ArgumentNullException( "coin" );
            }
            if ( quantity <= 0 ) {
                return false;
            }
            lock ( this._coins ) {
                if ( !this._coins.ContainsKey( coin ) || this._coins[ coin ] < quantity ) {
                    return false; //no coins to withdraw!
                }
                this._coins[ coin ] -= quantity;
                return true;
            }
        }
 
        public IEnumerator<KeyValuePair<IDenomination, UInt64>> GetEnumerator() {
            return this.Groups.GetEnumerator();
        }
 
        IEnumerator IEnumerable.GetEnumerator() {
            return this.GetEnumerator();
        }
 
        /// <summary>
        ///     Create an empty wallet with a new random id.
        /// </summary>
        /// <returns></returns>
        [NotNull]
        public static Wallet Create() {
            return new Wallet( id: Guid.NewGuid() );
        }
 
        /// <summary>
        ///     Create an empty wallet with the given <paramref name="id" />.
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [NotNull]
        public static Wallet Create( Guid id ) {
            return new Wallet( id: id );
        }
 
        public Boolean Contains( [NotNull] IBankNote bankNote ) {
            if ( bankNote == null ) {
                throw new ArgumentNullException( "bankNote" );
            }
            return this._bankNotes.ContainsKey( bankNote );
        }
 
        public Boolean Contains( [NotNull] ICoin coin ) {
            if ( coin == null ) {
                throw new ArgumentNullException( "coin" );
            }
            return this._coins.ContainsKey( coin );
        }
 
        public UInt64 Count( [NotNull] IBankNote bankNote ) {
            if ( bankNote == null ) {
                throw new ArgumentNullException( "bankNote" );
            }
            ulong result;
            return this._bankNotes.TryGetValue( bankNote, out result ) ? result : UInt64.MinValue;
        }
 
        public UInt64 Count( [NotNull] ICoin coin ) {
            if ( coin == null ) {
                throw new ArgumentNullException( "coin" );
            }
            ulong result;
            return this._coins.TryGetValue( coin, out result ) ? result : UInt64.MinValue;
        }
 
        public Boolean TryWithdraw( [CanBeNull] IDenomination denomination, UInt64 quantity ) {
            var asBankNote = denomination as IBankNote;
            if ( null != asBankNote ) {
                return this.TryWithdraw( asBankNote, quantity );
            }
 
            var asCoin = denomination as ICoin;
            if ( null != asCoin ) {
                return this.TryWithdraw( asCoin, quantity );
            }
 
            throw new NotImplementedException( String.Format( "Unknown denomination {0}", denomination ) );
        }
 
        /// <summary>
        ///     Deposit one or more <paramref name="denomination" /> into this <see cref="Wallet" />.
        /// </summary>
        /// <param name="denomination"></param>
        /// <param name="quantity"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        /// <remarks>Locks the wallet.</remarks>
        public Boolean Deposit( [NotNull] IDenomination denomination, UInt64 quantity, Guid? id = null ) {
            if ( denomination == null ) {
                throw new ArgumentNullException( "denomination" );
            }
            if ( quantity <= 0 ) {
                return false;
            }
 
            return this.Actor.Post( new TransactionMessage {
                Date = DateTime.Now,
                Denomination = denomination,
                ID = id ?? Guid.NewGuid(),
                Quantity = quantity,
                TransactionType = TransactionType.Deposit
            } );
        }
 
        private ulong Deposit( ICoin asCoin, UInt64 quantity ) {
            if ( null == asCoin ) {
                return 0;
            }
            try {
                lock ( this._coins ) {
                    UInt64 newQuantity = 0;
                    if ( !this._coins.ContainsKey( asCoin ) ) {
                        if ( this._coins.TryAdd( asCoin, quantity ) ) {
                            newQuantity = quantity;
                        }
                    }
                    else {
                        newQuantity = this._coins[ asCoin ] += quantity;
                    }
                    return newQuantity;
                }
            }
            finally {
                this.Statistics.AllTimeDeposited += asCoin.FaceValue * quantity;
            }
        }
 
        private ulong Deposit( IBankNote bankNote, UInt64 quantity ) {
            if ( null == bankNote ) {
                return 0;
            }
            try {
                lock ( this._bankNotes ) {
                    UInt64 newQuantity = 0;
                    if ( !this._bankNotes.ContainsKey( bankNote ) ) {
                        if ( this._bankNotes.TryAdd( bankNote, quantity ) ) {
                            newQuantity = quantity;
                        }
                    }
                    else {
                        newQuantity = this._bankNotes[ bankNote ] += quantity;
                    }
                    return newQuantity;
                }
            }
            finally {
                this.Statistics.AllTimeDeposited += bankNote.FaceValue * quantity;
            }
        }
    }
}

Thursday, October 17, 2013

10 Things You Maybe Didn’t Know About C# | Memory Fences

Here's a few code summaries:

1: You can create non-zero based arrays

static void Go() {
    string[] thingsThatHappenedInMyLife = (string[]) Array.CreateInstance(typeof(string), new[] { 24 }, new[] { 1990 });
 
    thingsThatHappenedInMyLife.SetValue("I was born", 1990);
    thingsThatHappenedInMyLife.SetValue("I dislocated my shoulder", 1996);
    thingsThatHappenedInMyLife.SetValue("I was allowed to buy alcohol (big mistake)", 2008);
    thingsThatHappenedInMyLife.SetValue("I started a programming blog", 2013);
 
    for (int i = thingsThatHappenedInMyLife.GetLowerBound(0); i <= thingsThatHappenedInMyLife.GetUpperBound(0); ++i) {
        string lifeEvent = (string)thingsThatHappenedInMyLife[i];
        if (lifeEvent == null) lifeEvent = "not much happened to me";
        Console.WriteLine("In " + i + ", " + lifeEvent);
    }
}


2: You can create unions in C# 

[StructLayout(LayoutKind.Explicit)]
public struct UnionTest {
    [FieldOffset(0)]
    public uint Value;
 
    [FieldOffset(0)]
    public readonly byte AsByte;
}

3: You can define extension methods with generic constraints on the extended type 

///
/// Returns the target object if it is not null; or throws a NullReferenceException if it is.
///
/// The target object's type.
/// The extended subject.
/// The message that will be passed to the generated exception. If null, then a default message will be used.
/// The object that NotNull was called on.
public static T NotNull(this T extended, string exceptionMessage = null)
    where T : class {
    if (extended == null) throw new NullReferenceException(exceptionMessage ?? "Supplied " + typeof(T).Name + " must not be null!");
    else return extended;
}
... and lots more ! Go read the blog !