Handy !
It is like a pre-RegEx handler..
Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts
Friday, August 29, 2014
Monday, February 17, 2014
C#: Deep Clone an Object onto another Object of the same type
/// <summary>
/// Copy each field in the <paramref name="source" /> to the matching field in the <paramref name="destination" />.
/// then
/// Copy each property in the <paramref name="source" /> to the matching property in the
/// <paramref name="destination" />.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="source"></param>
/// <param name="destination"></param>
/// <returns></returns>
public static Boolean DeepClone< TSource >( this TSource source, TSource destination ) {
if ( ReferenceEquals( source, destination ) ) {
return false;
}
if ( Equals( source, default( TSource ) ) ) {
return false;
}
if ( Equals( destination, default( TSource ) ) ) {
return false;
}
//copy all settable fields
// then
//copy all settable properties (going on the assumption that properties are the ones modifiying their private fields).
return CopyFields( source: source, destination: destination ) && CopyProperties( source: source, destination: destination );
}
/// <summary>
/// Copy the value of each field of the <paramref name="source" /> to the matching field in the
/// <paramref
/// name="destination" />
/// .
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="source"></param>
/// <param name="destination"></param>
/// <returns></returns>
public static Boolean CopyFields< TSource >( this TSource source, TSource destination ) {
try {
var sourceFields = source.GetType().GetAllFields();
var destFields = destination.GetType().GetAllFields();
foreach ( var field in sourceFields.Where( destFields.Contains ) ) {
CopyField( source: source, destination: destination, field: field );
}
return true;
}
catch ( Exception ) {
return false;
}
}
/// <summary>
/// Enumerate all fields of the <paramref name="type" />
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable< FieldInfo > GetAllFields( this Type type ) {
if ( null == type ) {
return Enumerable.Empty< FieldInfo >();
}
const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
return type.GetFields( flags ).Union( GetAllFields( type.BaseType ) );
}
public static void CopyField< TSource >( this TSource source, TSource destination, [NotNull] FieldInfo field, Boolean mergeDictionaries = true ) {
if ( field == null ) {
throw new ArgumentNullException( "field" );
}
try {
var sourceValue = field.GetValue( source );
if ( mergeDictionaries ) {
var sourceAsDictionary = sourceValue as IDictionary;
if ( null == sourceAsDictionary ) {
return;
}
var destAsDictionary = field.GetValue( destination ) as IDictionary;
if ( null == destAsDictionary ) {
return;
}
foreach ( var key in sourceAsDictionary.Keys ) {
try {
destAsDictionary[ key ] = sourceAsDictionary[ key ];
}
catch ( Exception exception ) {
exception.Log();
}
}
return;
}
field.SetValue( destination, sourceValue );
}
catch ( TargetException exception ) {
exception.Log();
}
catch ( NotSupportedException exception ) {
exception.Log();
}
catch ( FieldAccessException exception ) {
exception.Log();
}
catch ( ArgumentException exception ) {
exception.Log();
}
}
/// <summary>
/// Copy the value of each get property of the <paramref name="source" /> to each set property of the
/// <paramref
/// name="destination" />
/// .
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="source"></param>
/// <param name="destination"></param>
/// <returns></returns>
public static Boolean CopyProperties< TSource >( this TSource source, TSource destination ) {
try {
var sourceProps = source.GetType().GetAllProperties().Where( prop => prop.CanRead );
var destProps = destination.GetType().GetAllProperties().Where( prop => prop.CanWrite );
foreach ( var prop in sourceProps.Where( destProps.Contains ) ) {
CopyProperty( source: source, destination: destination, prop: prop );
}
return true;
}
catch ( Exception ) {
return false;
}
}
/// <summary>
/// Enumerate all properties of the <paramref name="type" />
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable< PropertyInfo > GetAllProperties( this Type type ) {
if ( null == type ) {
return Enumerable.Empty< PropertyInfo >();
}
const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
return type.GetProperties( flags ).Union( GetAllProperties( type.BaseType ) );
}
public static void CopyProperty< TSource >( this TSource source, TSource destination, PropertyInfo prop ) {
try {
var sourceValue = prop.GetValue( source, null );
prop.SetValue( destination, sourceValue, null );
}
catch ( TargetException exception ) {
exception.Log();
}
catch ( NotSupportedException exception ) {
exception.Log();
}
catch ( FieldAccessException exception ) {
exception.Log();
}
catch ( ArgumentException exception ) {
exception.Log();
}
}
Labels:
C#,
clone,
fields,
properties
Saturday, January 25, 2014
C#: Safely set the CheckBox.Checked property of a control across threads.
/// <summary>
/// Safely set the <see cref="CheckBox.Checked" /> of the control across threads.
/// </summary>
/// <param name="control"></param>
/// <param name="value"></param>
public static void Checked( [CanBeNull] this CheckBox control, Boolean value ) {
if ( null == control ) {
return;
}
if ( control.InvokeRequired ) {
control.BeginInvoke( new Action( () => {
control.Checked = value;
control.Refresh();
} ) );
}
else {
control.Checked = value;
control.Refresh();
}
}
C#: Generate a random Decimal (also generate a random Int32)
public static Decimal NextDecimal() {
return new Decimal( new[] { NextInt32(), NextInt32(), NextInt32(), NextInt32() } );
}
public static int NextInt32() {
unchecked {
var firstBits = Instance.Next( 0, 1 << 4 ) << 28;
var lastBits = Instance.Next( 0, 1 << 28 );
return firstBits | lastBits;
}
}
/// <summary>
/// A thread-local (threadsafe) <see cref="Random" />.
/// </summary>
public static Random Instance { get { return ThreadSafeRandom.Value; } }
private static readonly ThreadLocal<SHA256Managed> Crypts = new ThreadLocal<SHA256Managed>( valueFactory: () => new SHA256Managed(), trackAllValues: false );
/// <summary>
/// Provide to each thread its own <see cref="Random" /> with a random seed.
/// </summary>
public static readonly ThreadLocal<Random> ThreadSafeRandom = new ThreadLocal<Random>( valueFactory: () => {
var hash = Crypts.Value.ComputeHash( Guid.NewGuid().ToByteArray() );
var newSeed = BitConverter.ToInt32( hash, 0 );
return new Random( newSeed );
}, trackAllValues: false );
Friday, December 27, 2013
C#: Make a .NET form control flash.
/// <summary>
/// Flashes the control.
/// </summary>
/// <param name="control"></param>
/// <param name="spanOff"></param>
public static void Blink( [CanBeNull] this Control control, [CanBeNull] TimeSpan? spanOff = null ) {
if ( null == control ) {
return;
}
if ( !spanOff.HasValue ) {
spanOff = 333;
}
control.OnThread( () => {
var foreColor = control.ForeColor;
control.ForeColor = control.BackColor;
control.BackColor = foreColor;
control.Refresh();
} );
var timer = new Timer { AutoReset = false, Interval = spanOff.Value.TotalMilliseconds };
timer.Elapsed += ( sender, args ) => {
control.OnThread( () => {
control.ResetForeColor();
control.ResetBackColor();
control.Refresh();
} );
using ( timer ) { timer = null; }
};
GC.KeepAlive( timer );
timer.Start();
}
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;
}
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;
}
}
}
}
Wednesday, May 29, 2013
C#: Real world examples
I recommend buying the book: Real-World Functional Programming: With Examples in F# and C#
Saturday, March 17, 2012
Why C# Is Not My Favorite Programming Language
Why C# Is Not My Favorite Programming Language:
What a bunch of blarg...I love C#. I don't want to make my points by attacking the author personally, but the page is so full of "BS".
The example 'AutoLock' class as shown does not let you control when the lock is Unlocked. The lock() functionality in C# provides way better scoping.
I am supposed to remember to use
Um, YES... Using the language correctly will work wonders.
2. Object Lifetime is Not Determined by Scope
Lol. Not even going to honor this inaneness.
3. Every Function Must Be A Method
I repeat "Object Oriented". Why would you want a global non-namespaced function called "Sin"? Can you understand why that would be so bad? Btw, learn about C# extensions if you don't like the taste of this sugar.
4. Containers Have Algorithms As Methods
See my response to #2.
6. Operator Overloading Is Severely Broken
Only when you implement it wrong.
Conclusion: for someone so smart, you really need to grok C# and use it the correct way.
What a bunch of blarg...I love C#. I don't want to make my points by attacking the author personally, but the page is so full of "BS".
1. Default Object Lifetime Is Non-Deterministic
It is not supposed to be deterministic! It is this way on purpose so we can focus on what we want to do rather than worry about allocating and deallocating memory. Only a control freak would want to control every byte used.The example 'AutoLock' class as shown does not let you control when the lock is Unlocked. The lock() functionality in C# provides way better scoping.
I am supposed to remember to use
using, or litter my code with finally blocks.Um, YES... Using the language correctly will work wonders.
2. Object Lifetime is Not Determined by Scope
Lol. Not even going to honor this inaneness.
3. Every Function Must Be A Method
I repeat "Object Oriented". Why would you want a global non-namespaced function called "Sin"? Can you understand why that would be so bad? Btw, learn about C# extensions if you don't like the taste of this sugar.
4. Containers Have Algorithms As Methods
See my response to #2.
5. Default Comparison Behavior Is Dangerous
Dangerous? No. Gotcha-inducing, yes. When you don't pay attention to what you really intend to compare. Btw, I think the most Vector 'classes' are actually structs.. anywho...6. Operator Overloading Is Severely Broken
Only when you implement it wrong.
Conclusion: for someone so smart, you really need to grok C# and use it the correct way.
Subscribe to:
Posts (Atom)