C# – Tuples and Guid Struct

Tuples

Tuples are set of generic classes for holding a set of differently typed elements. Where each has read-only properties called Item1, Item2.

Creating Tuples

1. Using Constructor

var t = new Tuple (123, "Hello");

2. Static Helper method

Tuple t = Tuple.Create(123, "Hello");

3. Using Implicit Type

var t = Tuple.Create(123, "Hello");

Accessing the Tuple Properties

Console.WriteLine (t1.Item1 * 2);         // 246
Console.WriteLine (t1.Item2.ToUpper());   // HELLO

// The alternative sacrafices static type safety and causes boxing with value types:

object[] items = { 123, "Hello" };
Console.WriteLine ( ((int)    items[0]) * 2       );   // 246
Console.WriteLine ( ((string) items[1]).ToUpper() );   // HELLO

Tuples are convenient in returning more than one value from a method or creating collections of value pairs. Alternative to tuples is to use an object array but with limitations such as boxing and unboxing.

Comparing Tuples

Tuples are classes so reference types. The equality operator returns false where as the Equals method is overridden to compare each individual element.

var t1 = Tuple.Create (123, "Hello");
var t2 = Tuple.Create (123, "Hello");

Console.WriteLine (t1 == t2);           // False
Console.WriteLine (t1.Equals (t2));     // True

Guid Struct

The Guid struct represents a globally unique identifier: a 16-byte value when generated is almost unique in every way.

To instantiate an existing value, you use the constructors.

public Guid (byte[] b); //Accepts a 16-byte array
public Guid (string g); //Accepts a formatted string
//generate new unique Guid
Guid g = Guid.NewGuid ();
g.ToString().Dump ("Guid.NewGuid.ToString()");

Guid g1 = new Guid ("{0d57629c-7d6e-4847-97cb-9e2fc25083fe}");
Guid g2 = new Guid ("0d57629c7d6e484797cb9e2fc25083fe");
Console.WriteLine (g1 == g2);  // True

byte[] bytes = g.ToByteArray();
Guid g3 = new Guid (bytes);
g3.Dump();

Guid.Empty.Dump ("Guid.Empty");
default(Guid).Dump ("default(Guid)");
Guid.Empty.ToByteArray().Dump ("Guid.Empty - bytes");

C# – Working with Numbers

Working with Numbers

Conversions

Task Functions Examples
Parsing base 10 numbers Parse
TryParse
double d = double.Parse("3.5");
int i;
bool ok = int.TryParse("3", out i);
        
Parsing from base2, 8, or 16 Convert.ToIntegral
int i = Convert.ToInt32("1E", 16);
Formatting to hexadecimal ToString(“X”);
string hex = 45.ToString("X");
Lossless Numeric Conversion Implicit Cast
int i = 23;
double d = i;
Truncating Numeric Conversion Explicit Cast
double d = 23.5;
int i = (int) d;
Rounding numeric conversion (real to integral) Convert.ToIntegral
double d = 23.5;
int i = Convert.ToInt32(d);

Math

Lists the members of the static Math class.

Category Methods
Rounding Round, Truncate, Floor, Ceiling
Maximum/Minimum Max, Min
Absolute value and sign Abs, Sign
Square root Sqrt
Raising to a power Pow, Exp
Logarithm Log, Log10
Trigonometric Sin, Cos, Tan

Floor always rounds down, Ceiling always rounds up – even with negative numbers. If you have array or sequence of numbers, use Max and Min extension methods in System.Linq.Enumerable.

BigInteger

Lives in System.Numerics in namespace called System.Numerics.dll which allows you to represent an arbitrarily large integer without any loss of precision.

// BigInteger supports arbitrary precision.

BigInteger twentyFive = 25;      // implicit cast from integer

BigInteger googol = BigInteger.Pow (10, 100); 

// Alternatively, you can Parse a string: 
BigInteger googolFromString = BigInteger.Parse ("1".PadRight (100, '0'));

Console.WriteLine (googol.ToString());

double g1 = 1e100;                  // implicit cast
BigInteger g2 = (BigInteger) g1;    // explicit cast
g2.Dump ("Note loss of precision");

// This uses the System.Security.Cryptography namespace:
RandomNumberGenerator rand = RandomNumberGenerator.Create();
byte[] bytes = new byte [32];
rand.GetBytes (bytes);
var bigRandomNumber = new BigInteger (bytes);   // Convert to BigInteger
bigRandomNumber.Dump ("Big random number");

The advantage of storing such a number in a BigInteger over a byte is that you get value-type semantics. Calling ToByteArray converts a BigInteger back to a byte array.

Complex

Represents real and imaginary components of type double. Complex resides in the System.Numerics.dll assembly.

var c1 = new Complex (2, 3.5);
var c2 = new Complex (3, 0);

Console.WriteLine (c1.Real);       // 2
Console.WriteLine (c1.Imaginary);  // 3.5
Console.WriteLine (c1.Phase);      // 1.05165021254837
Console.WriteLine (c1.Magnitude);  // 4.03112887414927

Complex c3 = Complex.FromPolarCoordinates (1.3, 5);

// The standard arithmetic operators are overloaded to work on Complex numbers:
Console.WriteLine (c1 + c2);    // (5, 3.5)
Console.WriteLine (c1 * c2);    // (6, 10.5)

Complex.Atan (c1).Dump ("Atan");
Complex.Log10 (c1).Dump ("Log10");
Complex.Conjugate (c1).Dump ("Conjugate");

Random

The Random class generates a pseudorandom sequence of random bytes, integers or doubles. Before using Random, you need to instantiate first with or without seed.

Next(n) – generates a random integer between 0 and n-1.

NextDouble – generates a random double between 0 and 1.

NextByte – fills a byte array with random values.

Random is not considered for high-security applications instead cryptography should be used.

// If given the same seed, the random number series will be the same:
Random r1 = new Random (1);
Random r2 = new Random (1);
Console.WriteLine (r1.Next (100) + ", " + r1.Next (100));      // 24, 11
Console.WriteLine (r2.Next (100) + ", " + r2.Next (100));      // 24, 11

// Using system clock for seed:
Random r3 = new Random();
Random r4 = new Random();
Console.WriteLine (r3.Next (100) + ", " + r3.Next (100));      // ?, ?
Console.WriteLine (r4.Next (100) + ", " + r4.Next (100));      // ", "
// Notice we still get same sequences, because of limitations in system clock resolution.

// Here's a workaround:
Random r5 = new Random (Guid.NewGuid().GetHashCode());
Random r6 = new Random (Guid.NewGuid().GetHashCode());
Console.WriteLine (r5.Next (100) + ", " + r5.Next (100));      // ?, ?
Console.WriteLine (r6.Next (100) + ", " + r6.Next (100));      // ?, ?

// Random is not crytographically strong (the following, however, is):
var rand = System.Security.Cryptography.RandomNumberGenerator.Create();
byte[] bytes = new byte [4];
rand.GetBytes (bytes);       // Fill the byte array with random numbers.

BitConverter.ToInt32 (bytes, 0).Dump ("A cryptographically strong random integer");