Notes Page

This is a list of concrete examples, notes, and links to resources that I use for reference that I've compiled together from working on projects, reading books, and online articles. It's very incomplete, actively worked on, and it is by no means all-encompassing, ever finished, or meant to be a full resource for any of the listed topics. Please contact me if you find any errors or have comments/suggestions.

Expand all | Collapse all

SQL Server

Connections

SQL Server allows multiple instances of SQL Server to run at one time. They are just sparate loads into memory of the SQL Server engine running independently from each other. The default instance of your server will have the same name as your machine. Additional instances are named COMPUTERNAME$INSTANCENAME. If you connect to your SQL Server using (local), it will connect using Shared Memory, regardless of what NetLib you have selected. Shared memory gains you a high-performance connection. If you use your local PC's actual server name, then your communication will still go through the network stack and incur the overhead associated with that as if you were communicating with another system, regardless of the fact that it is on the same machine.

Naming Conventions

Tables
  • Use singular names rather than plural. Ex. Department instead of Departments
  • Primary Key: tablename_id. Example: department_id
Columns
  • Use singular rather than plural names
  • Foreign Keys should be named fk_tablename_id. Ex. In the user table, the department ID should be named fk_department_id
  • Date fields should have the suffix _on. Ex. created_on
  • Fields that record the user should be suffixed with _by. Ex. modified_by

Data Types

     

T-SQL

Opperators

=, <>, >, <, >=, <=, !=, !>, !<, AND, OR, NOT, BETWEEN, LIKE, IN, ALL, ANY, SOME, EXISTS

SELECT, WHERE, ORDER BY

Normal Selects
SELECT column_name
FROM table_name
WHERE column_name = value
ORDER BY some_column DESC, another_column;
                    
SELECT c.LastName FROM Person.Contact c;
Nested Subquery
SELECT DISTINCT o.OrderDate, od.ProductID
FROM Sales.SalesOrderHearder soh
JOIN Sales.SalesOrderDetail sod
    ON soh.SalesOrderID = sod.SalesOrderID
WHERE soh.orderDate = (Select MIN(OrderDate) FROM Sales.SalesOrderHeader)
                     
SELECT e.EmployeeID, FirstName, LastName
FROM HumanResources,Employee e
JOIN Person.Contact c
    ON e.ContactID = c.ContactID
WHERE e.EmployeeID IN
    (SELECT DISTINCT EmployeeID FROM HumanResources.JobCandidate)
                     
Correlated Subqueries
  1. The outer query obtains a record and passes it into the inner query
  2. The inner query executes based on the passed value(s)
  3. The inner query then passes the values from its results back out to the outer query, which uses them to finish its processing
SELECT o1.CustomerID, o1.SalesOrderID, o1.OrderDate
FROM Sales.SalesOrderHeader o1
WHERE o1.OrderDate = (Select MIN(o2.OrderDate)
                     FROM Sales.SalesOrderHEader o2
                     WHERE o2.CustomerID = o1.CustomerID)
ORDER BY CustomerID
                     
--Select the name of the customer and the first date they ordered something
SELECT c.LastName
    (SELECT MIN(OrderDate)
        FROM Sales.SalesORderHeader o
        WHERE o.ContactID = c.ContactID)
        AS "Order Date"
FROM Person.Contact c
                     
Derived Tables
--Find all the customers that ordered not only a minipump, but also the AWC Logo Cap

SELECT DISTINCT c.FirstName, c.LastName
    FROM Person.Contact AS c
    JOIN (SELECT ContactID
        FROM Sales.SalesOrderHeader AS soh
        JOIN Sales.SalesOrderDetail AS sod
            ON soh.SalesOrderID = sod.SalesOrderID
        JOIN Production.Product AS p
            ON sod.ProductID = p.ProductID
        WHERE p.Name = 'Minipump') pumps
      ON c.ContactID = pumps.ContactID
    JOIN (SELECT ContactID
        FROM Sales.SalesOrderHeader AS soh
        JOIN Sales.SalesOrderDetail AS sod
            ON soh.SalesOrderID = sod.SalesOrderID
        JOIN Production.Product AS p
            ON sod.ProductID = p.ProductID
        WHERE p.Name = 'AWC Logo Cap') caps
      ON c.ContactID = caps.ContactID
                     
ISNULL ISNULL(NULL, 5) returns 5 ISNULL(5, 15) returns 5 ISNULL(@MyVar, 0) where @MyVar IS NULL returns 0 ISNULL(@MyVar, 0) where @MyVar = 3 returns 3 ISNULL(@MyVar, 0) where @MyVar = 'Ronnie' returns Ronnie

GROUP BY, AGGREGATES

Once a GROUP BY is used, every column in the SELECT list has to either be part of the GROUP BY or be an aggregate. The HAVING clause is applied to the aggregated value for that group.
SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name;
                    

SELECT SalesOrderID, SUM(OrderQty)
FROM Sales.SalesOrderDetail
WHERE SalesOrderID BETWEEN 43684 AND 43686
GROUP BY SalesOrderID
HAVING SUM(OrderQty) > 5;
                    

DISTINCT, UNION

  • All UNIONed queries must have the same number of columns in the SELECT list.
  • The column headings are are taken only from the first query.
  • The default return option for UNION is DISTINCT. For all rows, use UNION ALL.
DISTINCT
SELECT DISTINCT column_name
FROM table_name;
UNION
SELECT column_name FROM table_name1
UNION
SELECT column_name FROM table_name2;
UNION ALL
SELECT column_name FROM table_name1
UNION ALL
SELECT column_name FROM table_name2;

INSERT

Example 1
INSERT INTO table_name (column1, column2, column3)
VALUES (value1, value2, value3);
SELECT NEWID = SCOPE_IDENTITY();
									
Example 2. Inserting values from another table
INSERT INTO table_name (column1, column2, column3)
SELECT item1, item2, item3
FROM another_table
									

UPDATE

Example 1.
UPDATE table_name
SET column1=value, column2=value2
WHERE some_column=some_value
									
Example 2. Update records in one table based on values in another table
UPDATE suppliers
SET supplier_name =
	(
	SELECT customers.name
	FROM customers
	WHERE customers.customer_id = suppliers.supplier_id
	)
WHERE EXISTS
	(
	SELECT customers.name
	FROM customers
	WHERE customers.customer_id = suppliers.supplier_id
	);
									

DELETE

DELETE FROM table_name
WHERE some_column=some_value
DELETE FROM Actors
FROM Actors a
LEFT JOIN Film f
  ON a.FilmID = f.FilmID
WHERE f.FilmID IS NULL;

JOINs

INNER JOIN

Returns only the records where there are matches. INNER JOINs are the default, so the INNER keyword is optional.
SELECT column_name
FROM table_name1
INNER JOIN table_name2
ON table_name1.column_name=table_name2.column_name
SELECT *
FROM HumanResources.Employee e
INNER JOIN HumanResources.Employee m
   ON e.ManagerID = m.EmployeeID;
SELECT e.EmployeeID, ce.FirstName
FROM HumanResources.Employee e
INNER JOIN HumanResources.Employee m
   ON e.ManagerID = m.EmployeeID;
INNER JOIN Person.Contact ce
   ON e.ContactID = ce.ContactID
INNER JOIN Person.Contact cm
   ON m.ContactID = cm.ContactID;
Reference a table multiple times
	SELECT *
	FROM Employees AS e
	INNER JOIN Reference AS r1
	     ON r1.ID = e.FirstID
	INNER JOIN Reference AS r2
	     ON r2.ID = e.SecondID
	INNER JOIN Reference AS r3
	     ON r3.ID = e.ThirdID
	INNER JOIN Reference AS r4
	     ON r4.ID = e.ForthID

OUTER JOIN (LEFT and RIGHT)

  • OUTER JOINs can often speed performance when used instead of other options that might produce the same result.
  • The first named table is considered as being on the left.
  • The second named table is considered as being on the right.
Left Outer Join
A LEFT JOIN says to include all records from the LEFT side regardless of whether there is a match on the RIGHT side or not.
SELECT column_name
FROM table_name1
LEFT OUTER JOIN table_name2
ON table_name1.column_name=table_name2.column_name
                        
Right Outer Join
A RIGHT JOIN says to include all records from the RIGHT side regardless of whether there is a match on the LEFT side or not.
SELECT column_name
FROM table_name1
RIGHT OUTER JOIN table_name2
ON table_name1.column_name=table_name2.column_name
                        

FULL JOIN

A FULL JOIN tells SQL Server to include all rows on both sides of the join.
SELECT *
FROM Film f
FULL JOIN Actors a
    ON f.FilmID = a.FilmId;
                        

CROSS JOIN

A CROSS join joins every record of one side of the join with every record on the other side of the join, which is the Cartesian product of all the records on both sides of the join.
SELECT *
FROM Film f
CROSS JOIN Actors a;
                        

Cast and Convert

  • CAST is ANSI compliant, and CONVERT isn't
  • CONVERT also does some date formatting conversions that CAST doesn't
SELECT 'The customer has an order numbered ' + CAST(SalesOrderID AS varchar)
FROM Sales.SalesOrderHeader
WHERE CustomerID = 5
                

Stored Procedures (sprocs) and User-Defined Functions (UDF)

User-Defined Functions (UDF)
  • Can return a value of most SQL Server types, excluding text, ntext, image, cursor, and timestamp.
  • All variables passed into the function are passed by value.
  • Recursion and nesting: 32 deep.

Creating, Altering Tables, Keys, and Constraints

Create the primary key on a new table
CREATE TABLE Customers
{
    CustomerNo  int IDENTITY    NOT NULL PRIMARY KEY,
    CustomerName    varchar(30) NOT NULL
}
                
Creating a primary key on an existing table
USE Accounting

ALTER TABLE Employees
    ADD CONSTRAINT PK_EmployeeID
    PRIMARY KEY (EmployeeID)
                
Creating Foreign Keys on new tables
USE Accounting

CREATE TABLE Orders
{
    OrderID  int IDENTITY    NOT NULL PRIMARY KEY,
    CustomerNo    int NOT NULL
        FOREIGN KEY REFERENCES Customers(CustomerNo)
}
                
Adding a Foreign key to an existing table
                    ALTER TABLE Orders
                        ADD CONSTRAINT FK_EmployeeCreatesOrder
                        FOREIGN KEY (EmployeeID) REFERENCES Employees(EmployeeID)
                
Cascading Actions
                    CREATE TABLE OrderDetails
                    {
                        OrderID  int NOT NULL,
                        PartNo varchar(10),
                        CONSTRAINT PKOrderDetails
                            PRIMARY KEY (OrderID, PartNo),
                        CONSTRAINT  FKOrderContainsDetails
                            FOREIGN KEY (OrderID)
                                REFERENCES Orders(OrderID)
                                ON UPDATE   NO ACTION
                                ON DELETE   CASCADE
                    }
                
Unique Constraints
UNIQUE doesn't automatically prevent you from having a NULL value. If you do allow NULLs, you will only be able to insert one of them. Although a NULL doesn't equal another NULL, they are considered to be duplicate from the perspective of a UNIQUE constraint.
                    CREATE TABLE Shippers
                    {
                        ShipperID  int NOT NULL,
                        ShipperName varchar(10),
                            UNIQUE
                    }
                
                    ALTER TABLE Employees
                    {
                        ADD CONSTRAINT AK_EmployeeSSN
                        UNIQUE (SSN)
                    }
                
Default Constraint
  • Defaults are used ony INSERT statements; they are ignored for UPDATE and DELETE statements.
  • If any value is supplied in the INSERT, the default isn't used.
  • If no value is supplied, the default will always be used.
                    CREATE TABLE Shippers
                    {
                        ShipperID  int NOT NULL,
                        ShipperName varchar(10),
                        DateInSystem    smalldatetime   NOT NULL
                            DEFAULT GETDATE ()
                    }
                
                    ALTER TABLE Customers
                    {
                        ADD CONSTRAINT CN_CustomerDefaultDateInSYstem
                            DEFAULT GETDATE() FOR DateInSystem
                    }
                
TODO: Rules, Defaults (not DEFAULT)

Indexes

  • Clustered Index: Only one clustered index per table is allowed. If an index is clustered, it means that the table on which the clustered index is based is physically sorted according to that index. Think of the page numbers in an encyclopedia.
  • Non-clustered Index: Can have many non-clustered indexes per table. Think of the keyword index at the back of the book.

Views

Peformance impacts of indexed views:
  • Views that reference multiple tables generally perform much faster with an indexed view because the join between the tables is preconstructed.
  • Aggregations performed in the view are precalculated and stored as part of the index. This means that the aggregation is performed one time (when the row is inserted or updated), and then can be read directly from the index information.
  • Inserts and deletes have higher overhead because the index on the view has to be updated immediately; updates also have higher overhead if the key column of the index is affected by the update

Scripts and Batches

TODO: Complete this section

Transactions and Locks

TODO: Complete this section

Triggers

TODO: Complete this section

Full-Text Search

TODO: Complete this section

System Databases

  • The master database: Critical to the database system and cannot be deleted since it keeps track of the system as a whole. Almost everything that describes your server is in the master database.
  • The model database: The model database on which future databases are based. Forms a template for any new database that you create.
  • The msdb database: Where SQL Agent process stores any system tasks such as scheduled backups.
  • The tempdb database: One of the key working areas for the server. When interim tables are built, they are built in this database. User created temporary tables are created here.

C#

Misc.

  • C# 1.0 is statically typed—the compiler knows what members to let you use
  • C# 1.0 is explicit—you have to tell the compiler what types variables have
  • C# 1.0 is safe—you can’t treat one type as if it were another without the availability of a genuine conversion.

Operators

Unary
+, -, !, ~, ++x, --x,(T)x, true, false, &, sizeof

Multiplicative
*, %

Additive
+,-

Shift
<<, >>

Relational and type testing
<,>,<=,>=,is,as

Equality
==, !=

Logical AND
&
int i = 0;
if (false & ++i == 1)
{
    // i is incremented, but the conditional
    // expression evaluates to false, so
    // this block does not execute.
}
            
Logical XOR
^

Logical OR
|

Conditional AND
&&
The conditional-AND operator performs a logical-AND of its bool operands, but only evaluates its second operand if necessary.

Conditional OR
||
The conditional-OR operator (||) performs a logical-OR of its bool operands, but only evaluates its second operand if necessary.

Conditional
?:

Assignment
=, +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, ??

Frameworks

Charting/Graphics
1. Microsoft Chart Controls

Compression/Zip
1. SharpZipLib
2. DotNetZip

Pdf Creators/Generators
1. PDFsharp
2. iTextSharp

Url Rewriting
1. url rewriter
2. UrlRewriting.Net

Dependency Injection
1. Unity Framework - Microsoft
2. StructureMap
3. Castle Windsor
4. NInject
5. Spring Framework

Logging
1. Logging Application Block - Microsoft
2. Log4Net - Apache
3. Error Logging Modules and Handlers(ELMAH)
4. NLog

Ajax
1. Ajax Control Toolkit - Microsoft

ORM
1. NHibernate

Unit Testing/Mocking
1. NUnit
2. Rhino Mocks
3. Moq
4. TypeMock.Net
5. xUnit.net

Automated Web Testing
1. Selenium

Misc
1. CSLA Framework - Business Objects Framework
2. AForge.net
3. Enterprise Library 4.1 - Logging, Exception Management, Validation, Policy Injection
4. File helpers library
5. Recaptcha

Escape Sequences

\' Single quotation mark
\" Double quotation mark
\\ Backslash
\0 Null
\a Alert
\b Backspace
\f Form feed
\n Newline
\r Carriage return
\t Tab character
\v Vertical tab
string s = @"C:\Program Files\"; The @ prefixed to a string literal treats the string at face value (even line breaks);

Loops

break can be used to exit from loops. Control will switch to the statement immediately after the end of the loop.

For loop
						for (int i=0;i<100;i++) {
						  //code
						}
						
While loop
						while (i<j) {
						  //code
						}
						
Do while loop
						do {
						  //code
						} while (i<j);
						
foreach loop
						foreach (int temp in arrayOfInts) {
						  //code
						}
						

Enumerations

public enum TimeOfDay {
  Morning = 0,
  Afternoon = 1,
  Evening = 2
}
Obtain an enum value from a string:
TimeOfDay time2 = (TimeOfDay) Enum.Parse(typeof(TimeOfDay), "afternoon", true);
Console.WriteLine((int)time2);

Arrays

  • If the elements of the array are value types, all values are copied when using clone(). Ex: int[] intArray2 = (int[])intArray1.Clone();
  • If the array contains reference types, only the references are copied, not the elements when calling the clone() method
  • A shallow clone copies the references but not the referenced objects. A deep clone copies the referenced objects as well. Shallow clones point to the same object when cloning reference types. Deep clones copy the referenced type as well.
  • If you need a deep copy of an array containing reference types, you have to iterate the array and create new objects.
  • Array.Copy() and Clone() creates shallow copies.
  • A shallow comparison is where the objects point to the same point in memory, whereas deep comparisons are working with values and properties of the object to deem equality.
int[] myArray = new int[32]; //creates a new array of 32 ints.
string[] str = new string[]{"a","b","c"};

foreach (string s in str)
    Console.WriteLine(s);
						
Multi Dimension Arrays
int[,] numbers = new int[3, 2] { {1, 2}, {3, 4}, {5, 6} };

for (int row = 0; row < numbers.GetLength(0); row++) {
    for (int column = 0; column < numbers.GetLength(1); column++) {
        Console.Write(numbers[row, column]);
        Console.Write(" ");
    }
    Console.WriteLine("");
}
						
Jagged Arrays
int[][] numbers = new int[][] { new int[] { 1, 3, 5 }, new int[] { 2, 4, 6, 8, 10 } };

for (int row = 0; row < numbers.Length; row++) {
    for (int column = 0; column < numbers[row].Length; column++){
        Console.Write(numbers[row][column]);
        Console.Write(" ");
    }
    Console.WriteLine("");
}
						
Sorting Array.Sort(someArray)

Properties

C# 3.5
						public int MyProperty { get; set; }
						
Prior to C# 3.5
						private int _myItem;

						public int MyItem
						{
						  get {
						    return myItem;
						  }
						  set {
						    myItem = value;
						  }
						}
Read Only
						private int _myItem;

						public int MyItem {
						  get {
						    return myItem;
						  }
						}
						

Namespaces

  • Microsoft recommends for most purposes you supply at least two nested namespaces names: the first one represents teh anme of your company, and the second one represent sthe name of the technology or software package of which the class is a member. Ex: YourCompanyName.SalesServices.Customer for the Customer class.
  • Namespace Aliases: using alias = YourCompanyName.SalesServices.Customer;
						namespace YourCompanyName.SalesServices {
						  class Customer {
						    //code
						  }
						}
						

XML Code Documentation

TODO: Finish this

Nullable types

            
//Example 1
decimal? price;
public decimal? Price
{
    get { return price; }
    private set { price = value; }
}
//Now we can do: Price = null;

//Example 2
int? x = 100;
if (x != null) {...}
            

The C# ?? null coalescing operator

The ?? operator checks whether the value provided on the left side of the expression is null, and if so it returns an alternate value indicated by the right side of the expression.

							string message = "hello world";
							string result = message ?? "It was null";
							//result == "hello world"

							string message = null;
							string result = message ?? "It was null";
							//result == "it was null"

							int? number = null;
							int result = number ?? 0;
							//result == 0
						
more info

Preprocessor Directives

TODO: Finish this. #define, #undef, #if, #elif, #else, #endif, #warning, #error, #region, #endregion, #line, #pragma

Errors and Exceptions

  • catch is optional
  • finally is optional
  • The order of the catch blocks are important
  • Having to many catch blocks can hurt performance
  • finally is executed whether or not an exception is thrown
  • When writing a library, it is normally best not to handle exceptions (unless you can fixe it), but to instead, assume that the calling code will handle any errors it encounters
  • It is perfectly legitimate to throw exceptions from catch and finally blocks
An example
                try {
                    if (index < 0)
                        throw new IndexOutOfRangeException("Index out of range");
                }
                catch (OverflowException ex) {
                    Console.WriteLine(ex.Message);
                }
                catch {

                }
                finally {

                }
            

Defining a User-Defined Exception Class
                class MyCustomException : ApplicationException {
                    public MyCustomException(string message)
                        : base(message)
                    {
                    }

                    public MyCustomException(string message, Exception innerException)
                        : base(message, innerException)
                    {
                    }
                }
            

Throwing and Catching a User-Defined Exception Class
                public void SomeMethod() {
                    //code ...

                    throw new MyCustomException("something info here");
                }

                public void SomeOtherMethod() {
                    try {

                    }
                    catch(MyCustomException ex) {

                    }
                }
            

Destructors, Idisposable, and using

Decontructor

Destructors in C# are really known as finalizers in the underlying .NET architecture. When a destructor is defined, what is emitted into the assembly by the compiler is actually a method called Finalize(). The problem with C# destructors as compared to their C++ counterparts is that they are nondeterministic, there is no way to know when an object's destructor will execute.

Also, C# destructors delay the final removal of an object from memory. Objects without a destructors are removed from memory with one pass of the garbage collector. Objects with a destructor require two: The first pass calls the destructor without removing the object, the second pass deletes the object.

            class MyClass {
                ~MyClass() {
                    //Code...
                }
            }
            

IDisposable

The recommended alternative to using a destructor is using the System.IDisposable interface.

            class MyClass : IDisposable {
                public void Dispose() {
                    //Code...
                }
            }
            

using

To dispose of an object, call the Dispose() method. The Dispose() call must be in the finally part of a try/catch or else you run the risk of failing to free the resources consumed by the object if an exception occurs. This is tedious, so use the using keyword.

            using (ResourceUser obj = new ResourceUser()) {
                //use the object
            }
            

This causes the variable to be scoped and when that variable goes out of scope, it's Dispose() method will be called automatically, even if an exception occurs.



Best practice
The best way to ensure that the Dispose() method is called is to use both a destructor and impliment IDisposable.
            //not thread safe
            using System;
            class ResourceHolder : IDisposable {
                private bool isDisposed = false;

                public void Dispose() {
                    Dispose(true);
                    GC.SuppressFinalize(this);
                }

                protected virtual void Dispose(bool disposing) {
                    if (!isDisposed) {
                        if (disposing) {
                            //Cleanup managed objects by calling their Dispose() methods
                        }
                        //Cleanup unmanaged objects
                    }
                    isDisposed = true;
                }

                ~ResourceHolder() {
                    Dispose (false);
                }

                public void SomeMethod() {
                    if(isDisposed) {
                        throw new ObjectDisposedException("This is disposed");
                    }

                    //Code...
                }
            }
            

Object and collection initializers (C# 3.0)

Person tom = new Person
{
    Name = "Tom",
    Age = 4,
    Home = { Town="Reading", Country="UK" },
    Friends =
    {
        new Person { Name = "Phoebe" },
        new Person("Abi"),
        new Person { Name = "Ethan", Age = 4 },
        new Person("Ben")
        {
            Age = 4,
            Home = { Town = "Purley", Country="UK" }
        }
    }
};

public class Person 
{
    public int Age { get; set; }
    public string Name { get; set; }
    
    List<Person> friends = new List<Person>();
    public List<Person> Friends { get { return friends; } }
    
    Location home = new Location();
    public Location Home { get { return home; } }
    
    public Person() { }
    
    public Person(string name)
    {
        Name = name;
    }
}
public class Location
{
    public string Country { get; set; }
    public string Town { get; set; }
}
        

Unsafe Code, pointers

  • & means "take the address of", and converts a value data type to a pointer. Ex. converts int to *int
  • * means "get the contents of this address", and converts a pointer to a value data type. Ex. converts *float to float
  • Can declare a pointer to any value type. Not possible to declare a pointer to a class or an array.
  • Pointers to structs can't contain any reference types
                unsafe class Myclass {
                    unsafe int* pX;

                    unsafe int DoSomething() {
                        //Code...
                    }
                }

                class MyClass2 {
                    void MyMethod() {
                        unsafe {
                            int x = 9;
                            int* pX, pY;
                            pX = &x;
                            pY = pX;
                            *pY = 75;
                            //so x = 75
                            Console.WriteLine("Address is " + (uint)pX);

                            void* pointerToVoid;
                            pointerToVoid = (void*)pX;

                            int x = sizeof(double); //sets x to 8

                            MyStruct Struct = new MyStruct();
                            pStruct = &Struct;

                            (*pStruct).X = 4;
                            //or you can do
                            pStruct->4;

                            //high performance arrays
                            double* pDoubles = stackalloc double[20];
                            *pDoubles = 3.0;
                            *(pDoubles+1) = 8.4;
                            pDoubles[2] = 4.5;
                        }
                    }
                }
            

Static

Data fields, member functions, properties and events can be declared either as static or non-static. Indexers in C# can't declared as static. Static constructors can't access non-static data members directly.

Static Field (Member variables)
						class MyClass {
						  public static int x;
						  public static int y = 1;
						}
						
Static Member Functions
A static member function can only access other static members.
						class MyClass {
						  private static int x = 1;
						  private static int y = 2;

						  public static void Method() {
						    Console.WriteLine("{0},{1}",x,y);
						  }
						}

						class MyOtherClass {
						  public static void Main() {
						    MyClass.Method();
						  }
						}
						
Static Constructors
							public class UserPreferences {
							    public static readonly int width;

							    static UserPreferences() {
							        width = 150;
							    }

							    private UserPreferences() {
							    }
							}

							//call the class...
							int w = UserPreferences.width;
							
Static Class
						static class Utilities {
						    public static void HelperMethod() { /* Code */ }
						}
						

Struct

  • A struct is a value type (not reference type).
  • Stored on the heap
  • Do not support inheritance
						struct Rectangle {
						    public double Length;
						    public double Width;
						}
						
						struct Rectangle {
						    public double Length;
						    public double Width;

						    Rectangle(double length, double width) {
						        Length=length;
						        Width=width;
						    }

						    public double Diagonal {
						        get {
						            return Math.Sqrt(Length*Length + Width*Width);
						        }
						    }
						}
						
						    foreach (KeyValuePair<int, string> kvp in myStringDict) {
                               Console.WriteLine("key " + kvp.Key);
                               Console.WriteLine("Value " + kvp.Value);
                            }
						

Interfaces

Interfaces implemented by collections

InterfaceMethods and PropertiesDescription
IEnumerable GetEnumerator() Required if a foreach statement is used with the collection.
ICollection Count, IsSynchronized, SynRoot, CopyTo() Implemented by collection classes. Extends IEnumerable
ICollection<T> Count, IsReadOnly, Add(), Clear(), Contains(), CopyTo(), Remove() Generic version of ICollection
IList IsFixedSize, IsReadOnly, Item, Add(), Clear(), Contains(), IndexOf(), Insert(), Remove(), RemoveAt() Allows you to access a collection using an indexer. Possible to insert or remove elements at any position.
IList<T> Item, IndexOf(), Insert(), RemoveAt()
IDictionary IsFixedSize, IsReadOnly, Item, Keys, Values, Add(), Clear(), Contains(), GetEnumerator(), Remove() Elements have a key and a value
IDictionary<TKey,TValue> Item, Keys, Values, Add(), ConatinsKey(), Remove(), TryGetValue()
ILookup<TKey,TElement> Count, Item, Contains() A new interface with .NET 3.5 that is used by collections that have multiple values for a key. The indexer returns an enumeration for a specified key.
IComparer<T> Compare() Used to sort elements inside a collection
IEqualityComparer<T> Equals(), GetHashCode() Implemented by a comparer that can be used for keys in a dictionary. Objects can be compared for equality.
		    public interface IDisposable {
		        void Dispose();
		    }
		    
		    class SomeClass : IDisposable {
		        public void Dispose() {
		            // code
		        }
		    }
		    

Inheritance

  • Modifiers: public, protected, internal, private, protected internal
  • Use base to call a base class version of a function
  • Both classes and functions can be declared as abstaract
  • An Abstract class cannot be instantiated
  • If a class is sealed, this means that you can't inherit from that class. In the case of a method, you can't override that method.
  • Interfaces can inherit from other interfaces
Declare that a class derives from another class
						class MyDerivedClass : MyBaseClass {
						    // functions and dta members here
						}
						
Declare that a class derives from another class and also from interfaces
						class MyDerivedClass : MyBaseClass, IInterface1, Interface2 {
						    // functions and dta members here
						}
						
Virtual Methods: By declaring a base class function as virtual, you allow the function (or property) to be overridden in any derived classes
							class  MyBaseClass {
							    public virtual string VirtualMethod() {
							        // code
							    }
							}
							
							class MyDerivedClass : MyBaseClass {
							    public override string VirtualMethod() {
							        return "This overrides the VirtualMethod() method";
							    }
							}
							
Abstract Classes and Functions
							abstract class MyAbstractBaseClass {
							    public abstract int CalculateArea(); //abstract method
							}
							
Sealed Classes and Methods
							sealed class FinalClass {
							    //code
							}
							
Adding Constructors with Parameters to a hierarchy
							class SomeDerivedClass : SomeBaseClass {
							    public SomeDerivedClass(int x, int y) : base (z) {
							        // code
							    }
							}
							
Interfaces
							public interface IDisposable {
							    void Dispose();
							}
							
							class SomeClass : IDisposable {
							    public void Dispose() {
							        // code
							    }
							}
							

Operator Overloading and User-Defined Casts

  • C# requires that all operator overloads be decalred as public and static.
  • Comaprison operators are required to be overloaded in pairs. If you overload ==, you must overload !=. The same for > and <. And also for >= and <=. All must return a bool.
  • If you overload == and !=, you must also overload Equals() and GetHashCode()
  • Use the checked and unchecked operator to force the CLR to envorce overflow checking.
Operator Overloading
						struct Vector {
						    public double x,y,z;

						    public Vector(double x, double y, double z) {
						        this.x = x;
						        this.y = y;
						        this.z = z;
						    }

						    public Vector(Vector rhs) {
						        x = rhs.x;
						        y = rhs.y;
						        z = rhs.z;
						    }

						    public static Vector opertaor + (Vector lhs, Vector rhs) {
						        Vextor result = new Vector(lhs);
						        result.x += rhs.x;
						        result.y += rhs.y;
						        result.z += rhs.z;

						        return result;
						    }

						    public static bool opertaor == (Vector lhs, Vector rhs) {
						        //code
						    }

						    public static bool opertaor != (Vector lhs, Vector rhs) {
						        return ! (lhs == rhs)
						    }
						}
						
User-Defined Casts
						struct Currency {
						    public uint Dollars;
						    public ushort Cents;

						    public Currency(uint dollars, ushort cents) {
						        this.Dollars = dollars;
						        this.Cents = cents;
						    }

						    public static implicit opoerator float (Currency value) {
						        return value.Dollars + (value.Cents/100.0f);
						    }

						    public static explicit operator Currency (float value) {
						        uint dollars = (uint)value;
						        ushort cents = (ushort)((value-dollars)*100);
						        return new Currency(dollars, cents);
						    }
						}
						

Extension Methods

Extension methods enable you to "add" methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. The extension method cannot access private members of the type it extends. Just a new syntax of invoking a static method. You can’t use just any method as an extension method—it has to have the following characteristics:

  • It has to be in a non-nested, nongeneric static class (and therefore has to be a static method).
  • It has to have at least one parameter.
  • The first parameter has to be prefixed with the this keyword.
  • The first parameter can’t have any other modifiers (such as out or ref).
  • The type of the first parameter must not be a pointer type.
                public static class StringExtension {
                    public static void Foo(this string s) {
                        Console.WriteLine("Foo invoked");
                    }
                }

                //now possible to use Foo() with the string type
                string s = "Hello";
                s.Foo();
            

Delegates

  • A predicate is a way of testing whether a value matches a criterion.
  • An action performs an action with the specified value.
public delegate bool Predicate<T> (T obj)
public delegate void Action<T> (T obj)


Example 1: An extended example
	        class BubbleSorter {
	            static public void Sort(object[] sortArray, Comparison comparison) {
	                for (int i=0;i<sortArray.Length;i++) {
	                    for (int j=i+1;j<sortArray.Length;j++) {
	                        if (comparison(sortArray[j], sortArray[i])) {
	                            object temp = sortArray[i];
	                            sortArray[i] = sortArray[j];
	                            sortArray[j] = temp;
	                        }
	                    }
	                }
	            }
	        }

	        class Employee {
	            private string name;
	            private decimal salary;

	            public Employee(string name, decimal salary) {
	                this.name = name;
	                this.salary = salary;
	            }

	            public static bool compareSalary(object x, object y) {
	                Employee e1 = (Employee) x;
	                Employee e2 = (Employee) y;
	                return (e1.salary < e2.salary);
	            }
	        }

	        //use it
	        class Program {
	            static void Main() {
	                Employee[] employees = {
	                  new Employee("B",20),
	                  new Employee("A",10)
	                };

	                BubbleSorter.Sort(employees, Employee.CompareSalary);

	                foreach (var employee in employees)
	                    Console.WriteLine(employee);
	            }
	        }
	        
Multicast Delegates
  • The order in which methods chained to the same delegate will be called is formally undefined.
  • When If one of the methods invoked by a a delegate throws an exception, the complete iteration stops. To avoid this, iterate the list on your own.
						delegate void DoubleOp(double value);

						DoubleOp operations = MathOperations.SomeOtherFunction;
						operations +=  MathOperations.SomeOtherFunction;
						
						DemoDelegate d1 = one;
						d1 += Two;

						Delegate[] delegates = d1.GetInvocationList();
						foreach (DemoDelegate d in delegates) {
						    try {
						        d();
						    }
						    catch (Exception) {
						        //error
						    }
						}
						

Anonymous Methods

Anonymous Methods: a block of code that is used as the parameter for the delegate.
//C# 2.0
List<Product> products = Product.GetSampleProducts();
products.Sort(delegate(Product first, Product second)
    { return first.Name.CompareTo(second.Name); }
);
						

//C# 3.0
List<Product> products = Product.GetSampleProducts();
products.Sort(
    (first, second) => first.Name.CompareTo(second.Name)
);
						

//define the delegate somewhere
delegate string DelegateTest(string val);


static void Main() {
    string mid = ", middle part,";

    DelegateTest anonDel = delegate(string param) {
        param += mid;
        param += " and this was added to the string.";
        return param;
    };

    Console.WriteLine(anonDel("start of string"));
}
						

Lambda Expressions

Lambda Expressions
//define the delegate somewhere
delegate string DelegateTest(string val);


static void Main() {
    string mid = ", middle part,";

    DelegateTest anonDel = param => {
        param += mid;
        param += " and this was added to the string.";
        return param;
    };

    Console.WriteLine(anonDel("start of string"));
}
						

Threading

Asynchronous Delegates

Asynchronous Delegates with polling
//using System.Threading;   
public delegate int TakesAWhileDelegate(int data, int ms);

static void Main(string[] args) {
    TakesAWhileDelegate d1 = TakesAWhile;
    IAsyncResult ar = d1.BeginInvoke(1, 3000, null, null);

    while (!ar.IsCompleted) {
        // do something in the main thread
        Console.Write(".");
        Thread.Sleep(50);
    }

    int result = d1.EndInvoke(ar);
    Console.WriteLine("result: {0}", result);
}

static int TakesAWhile(int data, int ms) {
    Console.WriteLine("TakesAWhile started");
    Thread.Sleep(ms);
    Console.WriteLine("TakesAWhile completed");
    return ++data;
}
	            

Asynchronous Delegates with Wait Handle
//using System.Threading;   
public delegate int TakesAWhileDelegate(int data, int ms);

static void Main(string[] args) {
    TakesAWhileDelegate d1 = TakesAWhile;
    IAsyncResult ar = d1.BeginInvoke(1, 3000, null, null);

    while (true) {
        // do something in the main thread
        Console.Write(".");
        if (ar.AsyncWaitHandle.WaitOne(50, false)) {
            Console.WriteLine("Done");
            break;
        }
    }

    int result = d1.EndInvoke(ar);
    Console.WriteLine("result: {0}", result);
}

static int TakesAWhile(int data, int ms) {
    Console.WriteLine("TakesAWhile started");
    Thread.Sleep(ms);
    Console.WriteLine("TakesAWhile completed");
    return ++data;
}
	            

Asynchronous Delegates with Wait Handle
//using System.Threading;
public delegate int TakesAWhileDelegate(int data, int ms);

static void Main(string[] args) {
    TakesAWhileDelegate d1 = TakesAWhile;

    d1.BeginInvoke(1, 3000, TakesAWhileCompleted, d1);

    for (int i = 0; i < 100; i++){
        Console.Write(".");
        Thread.Sleep(50);
    }
}

static int TakesAWhile(int data, int ms) {
    Console.WriteLine("TakesAWhile started");
    Thread.Sleep(ms);
    Console.WriteLine("TakesAWhile completed");
    return ++data;
}

static void TakesAWhileCompleted(IAsyncResult ar) {
    if (ar==null)
        throw new ArgumentNullException("ar");

    TakesAWhileDelegate d1 = ar.AsyncState as TakesAWhileDelegate;

    int result = d1.EndInvoke(ar);
    Console.WriteLine("result: {0}", result);
}
	        

Threading

  • The Thread class by default is a foreground thread. Set it to background by setting IsBackground
  • The process of the application keeps running as long as at least one foreground thread is running.
Figure 1. A Simple Example
using System;
using System.Threading;
class Program {
    static void Main(string[] args) {
        Thread t1 = new Thread(ThreadMain);
        t1.Name = "TestThread";
        t1.Start();
        Console.WriteLine("This is the main thred.");
    }

    static void ThreadMain() {
        Console.WriteLine("Thread: {0}", Thread.CurrentThread.Name);
    }
}
                
Figure 2. Passing data to threads through the constructor
using System;
using System.Threading;

public struct Data {
    public string Message;
}

class Program {
    static void Main(string[] args) {
        Data d = new Data();
        d.Message = "I want to pass this to the thread";
        Thread t1 = new Thread(ThreadMain);
        t1.Name = "TestThread";
        t1.Start(d);
        Console.Read();
    }

    static void ThreadMain(object o) {
        Data d = (Data)o;
        Console.WriteLine("Message: {0}", d.Message);
    }
}
                
Figure 3. Passing data to threads by creating a custom class
using System;
using System.Threading;

public class MyThread {
    private string data;

    public MyThread(string data) {
        this.data = data;
    }

    public void ThreadMain() {
        Console.WriteLine(data);
    }
}

class Program {
    static void Main(string[] args) {
        MyThread mt = new MyThread("This is my Thread");
        Thread t = new Thread(mt.ThreadMain);
        t.Start();
    }
}
                

Synchronization

  • lock, Interlocked, and Monitor can be used for synchronization within a process
  • The classes Mutex, Event, Semaphore, and ReaderWriterLockSlim also offer synchronization between threads of multiple processes.
lock
  • Only one thread can be inside the lock block for the state object.
  • Only reference types can be used for a lock.
  • The C# compiler resolves the lock statement to use the Monitor class.
  • Monitor as an advantage compared to the lock statement: you can add a timeout value waiting to get the lock.
using System;
using System.Threading;

public class AThreadingApplication {
    private object sync = new object();
    int state = 0;

    public void ThreadSafeMethod() {
        lock (sync) {
            //only one thread at a time can access this critical area
            if (state == 0)
                state++;
            state = 0;
        }
    }
}
                
Monitor
if (Monitor.TryEnter(obj, 1000)) { //wait 1 second
    try {
        //have a lock
    }
    finally {
        Monitor.Exit(obj);
    }
}
else {
    //1 second passed, didn't get the lock
}
                

Mutex

Mutex offers synchronization across multiple processes.

static class Program {
    [STAThread]
    static void Main() {
        bool cratedNew;
        Mutex mutex = new Mutex(false, "SingletonWinAppMutex", out createdNew);
        
        if (!createdNew) {
            MessageBox.Show("You can only start one instance of this application");
            Application.Exit();
            return;
        }
    }
}
                

Semaphore

Semaphore is similar to a mutex, but the semaphore can be used by multiple threads at once. A semaphore is a counting mutex, meaning that you can define the number of threads that are allowed to access the resource guarded by the semaphore simultaneously.

using System;
using System.Threading;
using System.Diagnostics;

class Program {
    static void Main() {
        int threadCount = 6;
        int semaphoreCount = 4;
        Semaphore semaphore = new Semaphore(semaphoreCount, semaphoreCount);
        Thread[] threads = new Thread[threadCount];

        for (int i = 0; i < threadCount; i++) {
            threads[i] = new Thread(ThreadMain);
            threads[i].Start(semaphore);
        }

        for (int i = 0; i < threadCount; i++)
            threads[i].Join();
        Console.WriteLine("All threads finished");
    }

    static void ThreadMain(object o) {
        Semaphore semaphore = o as Semaphore;
        Trace.Assert(semaphore != null, "o must be a Semaphore type");
        bool isCompleted = false;
        
        while (!isCompleted) {
            if (semaphore.WaitOne(600, false)) {
                try {
                    Console.WriteLine("Thread {0} locks the semaphore", Thread.CurrentThread.ManagedThreadId);
                    Thread.Sleep(2000);
                }
                finally {
                    semaphore.Release();
                    Console.WriteLine("Thread {0} releases the semaphore", Thread.CurrentThread.ManagedThreadId);
                    isCompleted = true;
                }
            }
            else {
                Console.WriteLine("timeout for thread {0}; wait again", Thread.CurrentThread.ManagedThreadId);
            }
        }
    }
}
                

Events

You can use events to inform other threads that some data is here, something is completed, and so on.

using System;
using System.Threading;

public struct InputData {
    public int X;
    public int Y;
    public InputData(int x, int y) {
        this.X = x;
        this.Y = y;
    }
}

public class ThreadTask
{
    private AutoResetEvent autoEvent;

    public int Result { get; private set; }

    public ThreadTask(AutoResetEvent ev) {
        this.autoEvent = ev;
    }

    public void DoSomeLongTask(object obj) {
        //do stuff
        autoEvent.Set();
    }
}

class Program {
    static void Main() {
        int taskCount = 4;
        AutoResetEvent[] autoEvents = new AutoResetEvent[taskCount];
        ThreadTask[] tasks = new ThreadTask[taskCount];

        for (int i = 0; i < taskCount; i++)  {
            autoEvents[i] = new AutoResetEvent(false);
            tasks[i] = new ThreadTask(autoEvents[i]);

            ThreadPool.QueueUserWorkItem(tasks[i].DoSomeLongTask, new InputData(1, 2));
        }

        for (int i = 0; i < taskCount; i++) {
            int index = WaitHandle.WaitAny(autoEvents);
            if (index == WaitHandle.WaitTimeout) {
                //timedout
            }
            else {
                Console.WriteLine("finished task {0}, result: {1}", index, tasks[index].Result);
            }
        }
    }
}
                

ReaderWriterLockSlim

Allows multiple readers, but just one writer, to a resource. ReaderWriterLockSlim is new to .net 3.0. The .net 1.0 ReaderWriterLock was replaced and redesigned to prevent deadlocks and to offer better performance.

BackgroundWorker

using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace WindowsFormsApplication1 {
    public struct CalcInput {
        public int x;
        public int y;
        public CalcInput(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }

        private void btnCalculate_Click(object sender, EventArgs e) {
            this.btnCalculate.Enabled = false;
            this.btnCancel.Enabled = true;
            backgroundWorker1.RunWorkerAsync(new CalcInput(2, 3));            
        }

        private void OnDoWork(object sender, DoWorkEventArgs e) {
            //In the backgroundWorker1 control, set the 
            //DoWork event to this

            //To enable progress, must enable WorkerReportsProgress to true;
            CalcInput input = (CalcInput)e.Argument;
            for (int i = 0; i < 10; i++) {
                System.Threading.Thread.Sleep(500);
                backgroundWorker1.ReportProgress(i*10);
                if (backgroundWorker1.CancellationPending) {
                    e.Cancel = true;
                    return;
                }
            }
            e.Result = input.x + input.y;
        }

        private void OnProgressChanged(object sender, ProgressChangedEventArgs e){
            //must set the ProgressChange event to this for the backgroundWorker1
            this.progressBar1.Value = e.ProgressPercentage;
        }

        private void OnWorkCompleted(object sender, RunWorkerCompletedEventArgs e) {
            //In the backgroundWorker1 control, set the 
            //RunWorkCompleted event to this
            if (e.Cancelled)
                this.txtResult.Text = "Cancelled";
            else
                this.txtResult.Text = e.Result.ToString();

            this.btnCalculate.Enabled = true;
            this.btnCancel.Enabled = false;
            this.progressBar1.Value = 100;
        }

        private void btnCancel_Click(object sender, EventArgs e) {
            //must set the WorkerSupportsCancellation to true
            //on backgroundWorker1 
            backgroundWorker1.CancelAsync();
        }
    }
}
            

Events

Strings

  • Use System.Text.StringBuilder to perform repeated modifications on a string
  • IFormattable

StringBuilder

StringBuilder sb = new StringBuilder("This is a string");
sb.AppendFormat(" This is appended to the string");
sb.Replace("i","R");
                

String.Format

Misc. examples of formating strings:
//dates
DateTime d = Convert.ToDateTime("3/17/2009 12:30:45 AM");
String s = "";
s = d.ToString("d");
s = d.ToString("D");
s = d.ToString("U");
s = d.ToString("y");
s = String.Format("{0:ddd}",d);
s = String.Format("{0:MM/dd/yyyy}",d);

//strings
String.Format("first: {0};second: {1}", "apple", "orange"); //"first: apple;second: orange"
String.Format(”{0:(###) ###-####}”, 8001234567); //(800) 123-4567

//numbers
decimal i = 25.00M;
String.Format("{0:C4}", i); //"$25.0000"
String.Format("{0:C2}", i); //"$25.00"
String.Format("{0:C}", i); //"$25.00"
String.Format("{0:C0}", i); //"$25"

String.Format("{0:00000}", 25); //"00025"

//only two decimal places
String.Format("{0:0.00}", 123.4567); //"123.46"
String.Format("{0:0.00}", 123.4); //"123.40"
String.Format("{0:0.00}", 123.0); //"123.00"

//maximum of two decimal places
String.Format("{0:0.##}", 123.4567); //"123.46"
String.Format("{0:0.##}", 123.4); //"123.4"
String.Format("{0:0.##}", 123.0); //"123"

//at least two digits before decimal point
String.Format("{0:00.0}", 123.4567); //"123.5"
String.Format("{0:00.0}", 23.4567); //"23.5"
String.Format("{0:00.0}", 3.4567); //"03.5"
String.Format("{0:00.0}", -3.4567); //"-03.5"

//leading and trailing zeros
String.Format("{0:0.0}", 0.0); //"0.0"
String.Format("{0:0.#}", 0.0); //"0"
String.Format("{0:#.0}", 0.0); //".0"
String.Format("{0:#.#}", 0.0); //""
                
Formatting Numbers
  • Leading Zeros: D, X
  • Trailing Zeros: C, E, F, N, P
SpecifierTypeFormatExample
CCurrenty{0:C}$4834.50
DInteger{0:D}4834
EScientific notation{0:E}4.834E+003
FFixed -point decimal{0:F}4834.50
GGeneral number{0:G}4834.5
Nlocale-specific format{0:N}4 384,50(Europe)
PPercentage{0:P}432,000.00%
XHexadecimal{0:X}ffffcfc6


Formatting Dates
SpecifierTypeExample
dShort Date08/06/1970
DLong Date01 June 1990
tShort Time12:30
TLong Time12:30:59
fFull date and time08 June 1970 12:30
FFull date and time (long)08 June 1970 12:30:59
gDefault date and time08/06/1970 12:30
GDefault date and time (long)08/06/1970 12:30:59
MDay / Month8 June
rRFC1123 date stringMon, 08 Jun 1970 12:30:59 GMT
sSortable date/time1970-06-08T12:30:59
uUniversal time, local timezone 1970-06-08 12:30:59Z
YMonth / YearJune 1970
ddDay08
dddShort Day NameMon
ddddFull Day NameMonday
hh2 digit hour12
HH2 digit hour (24 hour)12
mm2 digit minute30
MMMonth06
MMMShort Month nameJun
MMMMMonth nameJune
ssseconds59
ttAM/PMPM
yy2 digit year70
yyyy4 digit year1970
:{0:hh:mm:ss}12:30:59
/{0:dd/MM/yyyy}08/06/1970


Add specifiers to your classes
Assume you have a Vecotr struct and need to implement a way to format the ToString() in various ways.
							struct Vector : IFormattable {
							    public double x, y, z;

							    public string ToString(string format, IFormatProvider formatProvider) {
							        if (format ==  null)
							            return ToString();

							        string formatUpper = format.ToUpper();

							        switch (formatUpper) {
							            case "N":
							                return "|| " + Norm().ToString() + " ||";
							            case "VE":
							                return String.Format("( {0:E}, {1:E}, {2:E} )", x, y, z);
							            case "IJK":
							                StringBuilder sb = new StringBUilder(x.ToString(0,30);
							                sb.ApendFormat(" i + ");
							                sb.ApendFormat(y.ToString());
							                sb.ApendFormat(" j + ");
							                sb.ApendFormat(z.ToString());
							                sb.ApendFormat(" k");
							                return sb.ToString();
							            default:
							                return ToString();
							        }
							    }
							}

							//example:
							//Vector v1 = new Vector(1,32,5);
							//Console.WriteLine("The VE format is {0,30:VE}",v1);
             

Regular Expressions

System.Text.RegularExpressions. The .NET regular expression engine is designed to be mostly compatible with Perl 5 regular expressions, but with some added features.

Pattern Matching
A brief list of Regular Expression Language Elements. To escape a meta character, use the \. For example, to find a period, use \.
SymbolMeaning
^Beginning of input text (first character of the text)
$End of input Text
.Any single character except the newline character (\n)
*Preceding character may be repeated zero or more times
+Preceding character may be repeated one or more times
?Preceding character may be repeated zero or one time
\sAny whitespace character
\SAny character that isn't a whitespace
\bWord boundary. Ex. ion\b matches any word ending in ion
\BAny position that isn't a word boundry. Ex. \BX\B matches any X in the middle of a word.
[x|y]A match that contains alternative characters. Ex. [a|b] means one character that can be either a or b.
[a-z]A range. [a-z] indicates any single lowercase letter. [0-9] indicates a digit.
()Groups characters. Ex. (an)+ locates any recurrences of the sequence an.
\wMatch any alphanumeric character
\WMatch any character that is NOT alphanumeric
\dMatch any digit
\DMatch any character that isn't a digit
[^aeiou]Match any character that is not one of the characters a,e,i,o, or u
                string Pattern = "some text to match";
                string Text = "Lots of text ... and even more text";
                MatchCollection Matches = Regex.Matches(Text, Pattern, RegexOptions.IgnoreCase | RegexOptions. ExplicitCapture);

                foreach (Match NextMatch in Matches) {
                    Console.WriteLine(NextMatch.Index);
                    //NextMatch.Index: returns the index in the input text of where the match was found.
                }

                //find words begining with "n".
                Pattern = @"\bn";

                //find words ending with the sequence "ion"
                Pattern = @"ion\b";

                //beginning with the letter "a" and ending with "ion"
                Patter = @"\ba\S*ion\b";

                //Extract the protocol, address, and port from a URL
                Pattern = @"\b(\S+)://(\S+)(?::(\S+))?\b";

                //Match an IP address
                Pattern = @"(\d{1,3}\.){3}\d{1,3}";
            

Generics

One of the big advantages of generics is performance. Using value types with non-generic collection classes results in boxing and unboxing when the value type is converted to a reference type and vice versa. It is not possible to assign null to a generic type.
                List<int> list = new List<int>();
                list.Add(123);

                int i = list[0];  //no unboxing or casting needed
            
Creating Generic Classes
                public class LinkedListNode<T> {
                    private T value;

                    public LinkedListNode(T value) {
                        this.value = value;
                    }

                    public T Value {
                        get { return value; }
                    }

                    private LinkedListNode<T> next;

                    public LinkedListNode<T> Next; {
                        get {return next; }
                        internal set { next = value; }
                    }

                    // ... more code for linked lists
                }
            
Null values
It isn't possible to assign null to a generic type. Instead, you must use the default keyword. default initializes generic types either to null if it is a reference type or 0 if it is a value type. Example:
                public T DoSomething() {
                    T someThing = default(T);

                    return someThing;
                }
            
Constraints: force the type to implement a given interface. One more set of restrictions: the class you specify can’t be a struct, a sealed class (such as string), or any of the following “special” types: System.Object, System.Enum, System.ValueType, System.Delegate
                public class SomeClass<TGeneric> where TGeneric : ISomeInterface
                    //where T : struct
                    //where T : class
                    //where T : IFoo
                    //where T : Foo
                    //where T : new()
                    //where T1 : T2
                    
                class Sample<T> where T : Stream,IEnumerable<string>,IComparable<int>
                class Sample<T> where T : class, Stream, new()
                class Sample<T> where T : struct, IDisposable
                class Sample<T,U> where T : class where U : struct, T
                class Sample<T,U> where T : Stream where U : IDisposable
                
                //Invalid Examples
                class Sample<T> where T : class, struct
                class Sample<T> where T : Stream, class
                class Sample<T> where T : new(), Stream
                class Sample<T,U> where T : struct where U : class, T
                class Sample<T,U> where T : Stream, U : IDisposable
            
Inheritance
                public class Base<T> {

                }

                public class Derived<T> : Base<T>
                //or: public class Derived<T> : Base<string>
            
                public abstract class Calc<T> {
                    public abstract T Add(T x, Ty);
                    public abstract T Sub(T x, Ty);
                }

                public class SimpleCalc : Calc<int> {
                    public override int Add(int x, int y) {
                        return x + y;
                    }

                    public override int Sub(int x, int y) {
                        return x - y;
                    }
                }
            
Generic Interfaces
                public interface IComparable<T> {
                    int CompareTo(T other);
                }
            
Generic Methods
                void Swap<T>(ref T x, ref T y) {
                    T temp;
                    temp = x;
                    x = y;
                    y = temp;
                }

                void test() {
                    int i=8;
                    int j=9;

                    Swamp<int>(ref i, ref j);

                    //Because the C# compiler can get the type of the parameters
                    //by calling the Swap method, it is not
                    //required to assign the generic type with the method calld.

                    Swap(ref i, ref j);
                }
            
Nullable<T>
                Nullable<int> x;
                x=4;
                if (x.HasValue) {
                    //...
                }
                x = null;
            

Collections

Querying collections

//C# 3.0
List<Product> products = Product.GetSampleProducts();
foreach (Product product in products.Where(p => p.Price > 10)) {
    Console.WriteLine(product);
}
                

Lists

Example 1. Using List<T>
List<int> candidates = new List<int>();
for (int i=2; i <= 100; i++) {
    candidates.Add(i);
}

//public delegate bool Predicate<T> (T obj)
for (int factor=2; factor <= 10; factor++) {
    candidates.RemoveAll (
        delegate(int x) {return x>factor && x%factor==0;}
    );
}

//public delegate void Action<T> (T obj)
candidates.ForEach (delegate(int prime) 
    { Console.WriteLine(prime); }
);
            
Example 2.
                [Serializable]
                public class Racer : IComparable<Racer>, IFormattable {
                    public Racer() : this (String.Empty, String.Empty, String.Empty) {}

                    public Racer (String firstName, string lastName, string country)
                        : this(firstName, lastName, country, 0) {}

                    public Racer(string firstName, string lastName, string country, int wins) {
                        this.FirstName = firstName;
                        this.LastName = lastName;
                        this.Country = country;
                        this.Wins = wins;
                    }

                    public string FirstName { get; set; }
                    public string LastName { get; set; }
                    public string Country { get; set; }
                    public int Wins { get; set; }

                    public override string ToString() {
                        return String.Format("{0} {1}", FirstName, LastName);
                    }
                    public string ToString (string format, IFormatProvider formatProvider) {
                        switch (format.ToUpper()) {
                            case null:
                            case "N": //name
                                return ToString();
                            case "F":
                                return FirstName;
                            default:
                                throw new FormatException(String.Format(formatProvider, "Format not supported",format));
                        }
                    }

                    public string ToString(string format) {
                        return ToString(format, null);
                    }

                    public int CompareTo(Racer other) {
                        int compare = this.LastName.CompareTo(other.LastName);

                        if (compare == 0)
                            return this.FirstName.CompareTo(other.FirstName);
                        return compare;
                    }
                }

                //Now use this class in a List
                {
                    List<Racer> racers = new List<Racer>();
                    Racer r1 = racers[0];
                }
            

Queues

A queue is a collection where elements are processed firt in, first out (FIFO). You cannot access the queue using an indexer.

                Queue<int> q = new Queue<int>();
                q.Enqueue(3);
                int i = q.Dequeue();
            

Stacks

A stack is a collection where the item that is added last to the stack is read first (LIFO).

                Stack<int> s = new Stack<int>();
                s.Push(3);
                int i = s.Pop();
            

Linked Lists

A doubly linked list, where one element references the next and the previous one. The advantage of a linked list is that if items are inserted in the middle of a list, the linked list is very fast. Items of linked lists can be accessed only one after the other. It takes a long time to find an item that's somewhere in the middle or at th end of the list.

               LinkedList<int> numbers = new LinkedList<int>();

               numbers.AddFirst(1);
               numbers.AddFirst(2);
               numbers.AddBefore(numbers.Find(2), 3);
               numbers.AddAfter(numbers.Find(1), 4);

               foreach (int i in numbers) {
                  //...
               }
            

Sorted Lists

A sorted list that sorts elements based on a key. The important part of SortedList is that when you enumerate it, the entries come out sorted by key.

               SortedList<string, string> books = new SortedList<string, string>();
               books.Add("C# 3.5", "932-324-234324");

               books["C# 3.4"] = "983-345-234234";

               foreach  (KeyValuePair<string, string> book in books) {
                Console.WriteLine("{0}, {1}", book.Key, book.Value);
               }

               foreach (string isbn in books.Values) {
                Console.WriteLine(isbn);
               }

               foreach (string title in books.Keys) {
                //...
               }
            

Dictionaries

Dictionaries allow you to access elements based on a key. They are also known as hash tables or maps. Fast lookup using the key. Can add/remove elements without the performance overhead of having to shift subsequent items in memory. Supports only one value per key.

                Dictionary<string, int> d = new Dictionary<string, int>();
                d.Add("cat", 1);
                d.Add("dog", 4);
                d.Add("cow", 6);
                d.Add("rooster", -3);

                if (d.ContainsKey("dog")) {
                    int i = d["dog"];
                }

                if (d.TryGetValue("cow", out value)) {
                    d["cow"] = value + 1;
                }
            

Lookup

C# 3.5. System.Linq Maps keys to a collections of values.

                   List<Package> packages = new List<Package> { new Package { Company = "Coho Vineyard", Weight = 25.2, TrackingNumber = 89453312L },
                         new Package { Company = "Lucerne Publishing", Weight = 18.7, TrackingNumber = 89112755L },
                         new Package { Company = "Wingtip Toys", Weight = 6.0, TrackingNumber = 299456122L },
                         new Package { Company = "Contoso Pharmaceuticals", Weight = 9.3, TrackingNumber = 670053128L },
                         new Package { Company = "Wide World Importers", Weight = 33.8, TrackingNumber = 4665518773L } };

                    // Create a Lookup to organize the packages. Use the first character of Company as the key value.
                    // Select Company appended to TrackingNumber for each element value in the Lookup.
                    Lookup<char, string> lookup = (Lookup<char, string>)packages.ToLookup(p => Convert.ToChar(p.Company.Substring(0, 1)),
                           p => p.Company + " " + p.TrackingNumber);

                    // Iterate through each IGrouping in the Lookup and output the contents.
                    foreach (IGrouping<char, string> packageGroup in lookup) {
                        // Print the key value of the IGrouping.
                        Console.WriteLine(packageGroup.Key);
                        // Iterate through each value in the IGrouping and print its value.
                        foreach (string str in packageGroup)
                            Console.WriteLine("    {0}", str);
                    }

                    // This code produces the following output:
                    // C
                    //     Coho Vineyard 89453312
                    //     Contoso Pharmaceuticals 670053128
                    // L
                    //     Lucerne Publishing 89112755
                    // W
                    //     Wingtip Toys 299456122
                    //     Wide World Importers 4665518773
                    // Get the number of key-collection pairs in the Lookup.
                    int count = lookup.Count;

                    // Select a collection of Packages by indexing directly into the Lookup.
                    IEnumerable<string> cgroup = lookup['C'];

                    Console.WriteLine("\nPackages that have a key of 'C':");
                    foreach (string str in cgroup)
                        Console.WriteLine(str);

                    // This code produces the following output:
                    // Packages that have a key of 'C'
                    // Coho Vineyard 89453312
                    // Contoso Pharmaceuticals 670053128
                    // Determine if there is a key with the value 'G' in the Lookup.
                    bool hasG = lookup.Contains('G');
            

HashSet

An unordered list of distinct items. Inserting items is fast. Can create a union or intersections of sets.

                HashSet<string> hs1 = new HashSet<string>() { "a", "b", "c" };
                HashSet<string> hs2 = new HashSet<string>() { "b", "c", "d" };

                HashSet<string> hs3 = new HashSet<string>(hs1);
                hs3.UnionWith(hs2);

                if (hs1.Add("e"))
                    Console.WriteLine("e added");
                if (hs1.IsSubsetOf(hs2)) {
                    //...
                }
                if (hs1.IsSupersetOf(hs2)) {
                    //...
                }
                if (hs1.Overlaps(hs2)) {
                    //...
                }

                hs3.ExceptWith(hs2);
            

Bit Arrays

BitArray, BitVector32.BitarrayUsed to deal with a number of bits. BitArray is resizeable. BitVector32 is stack-based and therefore faster

Security, Encryption

Hash
  • MD5
  • MD5Cng
  • SHA1
  • SHA1Managed
  • SHA1Cng
  • SHA256
  • SHA256Managed
  • SHA256Cng
  • SHA384
  • SHA384Managed
  • SHA384Cng
  • SHA512
  • SHA512Managed
  • SHA512Cng
Symmetric Encryption: Uses the same key for encryption and decryption.
  • DES
  • DESCryptoServiceProvider
  • TripleDES
  • TripleDESCryptoServiceProvider
  • Aes
  • AesCryptoServiceProvider
  • AesManaged
  • RC2
  • RC2CryptoServiceProvider
  • Rijandel
  • RijandelManaged
Asymmetric Encryption: Uses different keys for encryption and decryption.
  • DSA
  • DSACryptoServiceProvider
  • ECDsa
  • ECDsaCng
  • ECDiffieHellman
  • ECDiffieHellmanCng
  • RSA
  • RSACryptoServideProvider

ADO.net

ADO.net namespaces and misc. notes

  • Be wary of any nondatabase-related code that executes while the connection is open.
  • It's best to open connections late and close them as early as possible
  • DataAdapter object's Fill and Update methods can open and close a connection automatically
  • Avoid passing an open connection between methods where possible
  • To retrieve a single value, ExecuteReader and Fill methods are usually overkill. It's More efficient to use the ExecuteScalar method.
  • Moving queries to a stored procedure can offer greater performance since the execution plan will be stored in the procedure cache
ADO.net namespaces
  • System.Data: All generic data access classes
  • System.Data.Common: Classes shared (or overridden) by individual data providers
  • System.Data.Odbc: ODBC provider classes
  • System.Data.OleDb: OLE DB provider class
  • System.Data.ProviderBase: Base classes and connection factory classes
  • System.Data.Oracle: Oracle provider classes
  • System.Data.Sql: Generic interfaces and classes for SQL server data access
  • System.Data.SqlClient: SQL Server provider classes
  • System.Data.SqlTypes: SQL Server data types

Connection Strings

SQL Server 2005/2008
Server=(local);Database=SomeDatabase;Integrated Security=True;

SQL Express 2005
Server=localhost\SQLEXPRESS;Database=SomeDatabase;Integrated Security=True;

More connections strings can be found at: connectionstrings.com

Executing Queries: Create, open, and close a connection to a database

Step 1: Store the connection information in a configuration file
<configuration>
  <configSections/> 
  <appSettings/>
  <connectionStrings>
    <add name="MyDatabase" providerName="System.Data.SqlClient" connectionString="Server=localhost\SQLEXPRESS;Database=SomeDatabase;Integrated Security=True;"/>
  </connectionStrings>
</configuration>
        	    
ExecuteNonQuery
private int ExecuteNonQuery() {
    ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["MyDatabase"];
    string sql = "UPDATE users SET username=@username WHERE user_id=@user_id";
    int rowsAffected = 0;

    using (SqlConnection conn = new SqlConnection(settings.ConnectionString)) {
        using (SqlCommand cmd = new SqlCommand(sql, conn)) {
            cmd.Parameters.Add("username", SqlDbType.NVarChar, 20).Value = "New Username";
            cmd.Parameters.Add("user_id", SqlDbType.Int).Value = 5;
            conn.Open();
            rowsAffected = cmd.ExecuteNonQuery();
        }
    }
    return rowsAffected;
}
                
ExecuteScalar
private string ExecuteScalar() {
    ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["MyDatabase"];
    string sql = "SELECT username FROM users WHERE user_id=@user_id";
    string username = "";

    using (SqlConnection conn = new SqlConnection(settings.ConnectionString)) {
        using (SqlCommand cmd = new SqlCommand(sql, conn)) {
            cmd.Parameters.Add("user_id", SqlDbType.Int).Value = 5;
            conn.Open();
            username = (string)cmd.ExecuteScalar();
        }
    }
    return username;
}
                
ExecuteReader
private void ExecuteReader() {
    //bad idea to return datareaders since it keeps the connection opened
    ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["MyDatabase"];
    string sql = "SELECT * FROM users WHERE user_id>=@user_id";

    using (SqlConnection conn = new SqlConnection(settings.ConnectionString)) {
        using (SqlCommand cmd = new SqlCommand(sql, conn)) {
            cmd.Parameters.Add("user_id", SqlDbType.Int).Value = 0;
            conn.Open();

            //using (SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection | CommandBehavior.SingleRow | ...))
            using (SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)) {
                while (dr.Read())
                    Response.Write(dr["username"]);
            }
        }
    }
}
                
Use a DataAdapter
private DataSet ExecuteSqlDataAdapter() {
    ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["MyDatabase"];
    string sql = "SELECT * FROM users WHERE user_id>=@user_id";
    DataSet ds = new DataSet();

    using (SqlConnection conn = new SqlConnection(settings.ConnectionString)) {
        using (SqlCommand cmd = new SqlCommand(sql, conn)) {
            cmd.Parameters.Add("user_id", SqlDbType.Int).Value = 0;
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            conn.Open();
            da.Fill(ds, "Users");
        }
    }

    return ds;
}
                

Calling Stored Procedures

Calling a stored procedure that returns nothing
private void ExecuteStoredProcedure() {
    ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["MyDatabase"];
    string sql = "sp_UpdateUser";

    using (SqlConnection conn = new SqlConnection(settings.ConnectionString)) {
        using (SqlCommand cmd = new SqlCommand(sql, conn)) {
            conn.Open();
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Add(new SqlParameter("@UserID", 1));
            cmd.Parameters.Add(new SqlParameter("@Username", "abc123"));
            cmd.ExecuteNonQuery();
        }
    }
}
                
Calling a stored procedure that uses a DataReader
private void ExecuteStoredProcedure() {
    ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings["MyDatabase"];
    string sql = "sp_GetUsers";

    using (SqlConnection conn = new SqlConnection(settings.ConnectionString)) {
        using (SqlCommand cmd = new SqlCommand(sql, conn)) {
            conn.Open();
            cmd.CommandType = CommandType.StoredProcedure;

            using (SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection)) {
                while (dr.Read())
                    Response.Write(dr["username"]);
            }
        }
    }
}
                

Taking Advantage of Output Parameters

In Figure 1 the DataSet would contain the data and all of the supporting metadata as overhead. The stored procedure in Figure 2 can be called from ADO.NET using a Command object. Its values can be retrieved using the Command object's parameter collection. The prGet_Customer (Figure 2) stored procedure is more efficient since it does not need to pass a rowset nor does the client code have to bear the weight of the extra overhead that comes with the DataSet. The three values can be stored in variables requiring less than 100 bytes. In contrast, if you return the same three values into a DataSet from a DataAdapter using the first stored procedure, the DataSet and its schema will be almost 1,000 bytes in size. If all you need are a handful of values from a single row, using the ExecuteScalar or output parameters executes faster than retrieving a rowset into a DataSet, and then having to pass that data to another application tier.

Figure 1 (bad way)
CREATE PROCEDURE prGet_CustomerRowSet
    @sCustomerID NCHAR(5)
AS
    SELECT CompanyName, ContactName, City
    FROM Customers
    WHERE CustomerID = @sCustomerID
GO
Figure 2 (better way)
CREATE PROCEDURE prGet_Customer
    @sCustomerID NCHAR(5),
    @sCompanyName NVARCHAR(40) OUTPUT,
    @sContactName NVARCHAR(30) OUTPUT,
    @sCity NVARCHAR(15) OUTPUT

AS
    SELECT @sCompanyName = CompanyName,
           @sContactName = ContactName,
           @sCity = City
    FROM Customers
    WHERE CustomerID = @sCustomerID
GO
Figure 3. Using the ouput parameters in Figure 2.
private void GetOutputValues() {
    string connectionString = "Server=(local);Database=Northwind;Integrated Security=True;";
    string sProc = "prGet_Customer";
    using (SqlConnection conn = new SqlConnection(connectionString)) {
        using (SqlCommand cmd = new SqlCommand(sProc, conn)) {
            conn.Open();
            cmd.CommandType = CommandType.StoredProcedure;

            cmd.Parameters.Add("@sCustomerID", SqlDbType.NChar, 5);
            cmd.Parameters["@sCustomerID"].Value = "abcde";

            cmd.Parameters.Add("@sCompanyName", SqlDbType.NVarChar, 40);
            cmd.Parameters["@sCompanyName"].Direction =  ParameterDirection.Output;

            cmd.Parameters.Add("@sContactName", SqlDbType.NVarChar, 30);
            cmd.Parameters["@sContactName"].Direction =  ParameterDirection.Output;

            cmd.Parameters.Add("@sCity", SqlDbType.NVarChar, 15);
            cmd.Parameters["@sCity"].Direction =  ParameterDirection.Output;

            cmd.ExecuteNonQuery();

            string sCompanyName =  cmd.Parameters["@sCompanyName"].Value.ToString();
            string sContacName =  cmd.Parameters["@sContactName"].Value.ToString();
            string sCity = cmd.Parameters["@sCity"].Value.ToString();
        }
    }
}
                    

Transactions

SqlTransaction oTran = null;
try {
    oCn.Open();
    oTran = oCn.BeginTransaction();

    oCmd1.Transaction = oTran;
    oCmd1.ExecuteNonQuery();

    oCmd2.Transaction = oTran;
    oCmd2.ExecuteNonQuery();

    oTran.Commit();
}
catch {
    oTran.Rollback();
    throw;
}
finally {
    oCn.Close();
}

More reading and references

LINQ: Language Integrated Query

When query expressions are defined during runtime, the query does not run. The query runs when the items are iterated (Deferred Query Execution).



Standard Query Operators
Where, OrderByDescending, Select, Where OfType<TResult>, SelectMany, OrderBy, ThenByDescending, Reverse, Join, GroupJoin, GroupBy, Any, All, Contains, Take, Skip, TakeWhile, SkipWhile, Distinct, Union, Intersect, Except
            //Assume we have a Formula1 class
                var query = from r in Formula1.GetChampions()
                            where r.Country == "Brazil"
                            orderby r.Wins descending
                            select r;

                foreach (Racer r in query) {
                    //...
                }

                //more examples
                var racers = from r in Formula1.GetChampions()
                             where r.Wins > 15 &&
                                (r.Country == "Brazil" || r.Country == "Austria")
                             select r;

                //Filtering with Index: Overload of the Where() method
                var racers = Formula1.GetChampions().
                             Where ((r, index) =>
                                r.LastName.StartsWith("A") &&
                                index % 2 != 0;


                object[] data = {"one", 2, 3, "four", "five"};
                var query = data.OfType<string>();

                //Compound from
                var ferrariDrivers = from r in
                                     Formula1.GetChampions()
                                     from c in r.Cars
                                     where c == "Ferrari"
                                     orderby r.LastName
                                     select r.FirstName + " " + r.LastName;

                //sorting
                var racers = from r in Formula1.GetChampions()
                             where r.Country == "Brazil"
                             orderby r.Wins descending
                             select r;

                //grouping
                var countries = from r in
                                Formula1.getChampions()
                                group r by r.Country into g
                                orderby g.Count() descending, g.Key
                                where g.Count() >= 2
                                select new { Country = g.Key, Count = g.Count() };

                //grouping with Nested Objects
                var countries = from r in
                                Formula1.getChampions()
                                group r by r.Country into g
                                orderby g.Count() descending, g.Key
                                where g.Count() >= 2
                                select new {
                                    Country = g.Key,
                                    Count = g.Count(),
                                    Racers = from r1 in g
                                        orderby r1.LastName
                                        select r1.FirstName + " " + r1.LastName
                                };

                //join
                var racersAndTeams =
                    from r in racers
                    join t in teams on r.year equals t.year
                    select new {
                        Year = r.Year,
                        Racer = r.Name,
                        Team = t.Name
                    }

               //set operations destinct, union, intersect, except

               //Partitioning

               //Aggregate Operators
               var query = from r in Formula1.GetChampions()
                        where r.Years.Count() > 3
                        orderby r.Years.Count() descending
                        select new {
                            Name = r.FirstName + " " + r.lastName,
                            TimesChampion = r.Years.count()
                        }

                //Conversions
                List<Racer> racers =
                    (from r in Formula1.GetChampions()
                    where r.Starts > 150
                    orderby r.Stars descending
                    select r).ToList();

                //Generation Operators: range, empty, repeat

                //Expression Trees

                //
            

web.config and settings files

Settings.Settings
In a Windows Forms project, there is a folder called Properties and a file called Settings.settings in that folder. Open the Settings.Settings file by double clicking it. The settings file contains two scopes: Application and User.

Application Scope: Not changed by the user. It is constant in every instance of the application.
User Scope: The setting is not constant throughout each instance. It is reset for each user installation.
						//save a value name "DefaultSavePath"
						Properties.Settings.Default.DefaultSavePath = TextBox1.Text;
						Properties.Settings.Default.Save();

						//use the settings
						TextBox1.Text = Properties.Settings.Default.DefaultSavePath;
					

web.config
TODO: flush this out

DateTime, Date, Time

Difference between two times

DateTime startTime = DateTime.Now;
DateTime endTime = DateTime.Now.AddSeconds(1234);
TimeSpan span = endTime.Subtract(startTime);

Console.WriteLine("Seconds different: " + span.Seconds);
Console.WriteLine("Minutes different: " + span.Minutes);
Console.WriteLine("Hours different: " + span.Hours);
Console.WriteLine("Days different: " + span.Days);
						

Timers

4 types of timers
  • System.Timers.Timer
  • System.Threading.Timer
  • System.Windows.Forms.Timer
  • System.Web.UI.Timer

Send Email

Add SMTP info to web.config or app.config
						<?xml version="1.0" encoding="utf-8" ?>
						<configuration>
						  <configSections >
						  </configSections>
						  <system.net>
						    <mailSettings>
						      <smtp from="example@gmail.com" deliveryMethod="Network">
						        <network host="smtp.gmail.com" port="587" userName="example@gmail.com" password="password" />
						      </smtp>
						    </mailSettings>
						  </system.net>
						</configuration>
					
Send the email in your program
						//using System.Net.Mail;

						var message = new MailMessage();
						message.To.Add(new MailAddress("john@example.com", "Mailer"));
						message.Body = "Test email";
						message.Subject = "Subject";

						var client = new SmtpClient();
						client.EnableSsl = true;
						client.Send(message);
					

Files and Directories

File, FileInfo, Directory, and DirectoryInfo:

  • Directory and File contain only static methods and are never instantiated.
  • DirectoryInfo and FileInfo implement roughly the same methods, properties, and constructors as Directory and File, but are stateful and the members are not static. Must instantiate these classes before they are used. More efficient if you are doing multiple operations on the same files/folders.
//using System.IO;
DirectoryInfo dir = new DirectoryInfo(@"C:\Program Files");
FileInfo f = new FileInfo(@"C:\file.txt");

f.CopyTo(@"C:\copy.txt");
File.Copy(@"C:\file.txt", @"C:\copy.txt");
File.Delete(@"C:\file.txt");
textbox1.Text = File.ReadAllText(@"C:\copy.txt");
                
Select a directory and list files in the directory
//using System.IO;

DirectoryInfo dir = new DirectoryInfo("c:\\");
FileInfo[] files = dir.GetFiles();
foreach (FileInfo f in files) {
    MessageBox.Show(f.FullName);
}
				

Read and Writing text files

Text files: If the file contains text, it is more convenient to read and write it using the StreamReader and StreamWriter class instead of the FileStream class.
Read text file
//using System.IO;
StreamReader sr = new StreamReader(@"C:\file.txt");

int nextChar = sr.Read(); //read a single character

int nChars = 100;
char[] charArray = new char[nChars];
int nCharsRead = sr.Read(charArray, 0, nChars);

string nextLine = sr.ReadLine(); //read an entire line
string restOfFile = sr.ReadToEnd(); //read remainder of the file/stream

sr.Close();
                
Write text file
//using System.IO;
StreamWriter sw = new StreamWriter(@"C:\file.txt");
sw.Write("This is a new line");
sw.Write('a');
char[] charArray = new char[100];
sw.Write(charArray);
sw.Close();

//create new text file
FileInfo file = new FileInfo(@"C:\newfile.txt");
StreamWriter sw2 = file.CreateText();
sw2.Close();
                

Read and Writing binary files

  • FileStream is intended for reading and writing binary data in a binary file
//using System.IO;
FileStream fs = new FileStream(@"C:\file.doc", FileMode.Create);

int nextByte = fs.ReadByte();

//read an arry of bytes
int nBytesRead = fs.Read(ByteArray, 0, 8);

byte newByte = 100;
fs.WriteByte(newByte);

//write an array of bytes
fs.Write(ByteArray, 0, nBytes);

fs.Close();
                    

Reading Drive Information

  • DriveInfo provides information on system drives
//using System.IO;
//list drives on system
DriveInfo[] driveArray = DriveInfo.GetDrives();
foreach (DriveInfo d in driveArray)
    Console.WriteLine(d.Name);

DriveInfo di = new DriveInfo("c");
Console.WriteLine(di.VolumeLabel);
Console.WriteLine(di.TotalFreeSpace);
Console.WriteLine(di.TotalSize);
Console.WriteLine(di.DriveFormat);
                    

OpenFileDialog: Select multiple files and bind to a gridview

							System.Windows.Forms.OpenFileDialog FileOpen = new System.Windows.Forms.OpenFileDialog();
							FileOpen.Multiselect = true;

							if (FileOpen.ShowDialog() == DialogResult.OK) {
							    string[] filename = FileOpen.FileNames;

							    for (int i=0; i < filename.Length; i++) {
							        DataGridViewRow row = new DataGridViewRow();
							        DataGridViewCell cell;

							        cell = new DataGridViewTextBoxCell();
							        cell.Value = filename[i];
							        row.Cells.Add(cell);

							        cell = new DataGridViewTextBoxCell();
							        row.Cells.Add(cell);

							        gridview.Rows.Add(row);
							    }
							}
							

FolderBrowserDialog: Select a folder and return the path

							FolderBrowserDialog folderBrowserDialog1 = new FolderBrowserDialog();

							if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) {
							    MessageBox.Show(folderBrowserDialog1.SelectedPath);
							}
							

Drag and Drop

This example uses a DataGridView to perform DragAndDrop.

First, for the DataGridView, enable AllowDrop to true.

Next, implement the DragEnter event.
private void MyDataGridView_DragEnter(object sender, DragEventArgs e) {
    //make sure a file is dropped, nothing else
    if (e.Data.GetDataPresent(DataFormats.FileDrop, false) == true)
        e.Effect = DragDropEffects.All;
}
			
Next, implement the DragDrop event of the target control (DataGridView).
private void MyDataGridVie_DragDrop(object sender, DragEventArgs e) {
    //get the files names dropped
    string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);

    //process files...
}
			

Windows Registry

  • CreateSubKey creates the key if it does not already exist. If it doesn't exist, it will return a RegistryKey instance that represents the existing key.
//using Microsoft.Win32;

//read access
RegistryKey hklm = Registry.LocalMachine;
RegistryKey hkSoftware = hklm.OpenSubKey("Software");
RegistryKey hkMicrosoft = hklm.OpenSubKey("Microsoft");

//read/write access
RegistryKey hklm2 = Registry.LocalMachine;
RegistryKey hkSoftware2 = hklm.OpenSubKey("Software",true);
RegistryKey hkNew = hkSoftware2.CreateSubKey("NewKey");
hkNew.SetValue("NewStringValue", "Hello World");
hkNew.SetValue("NewIntValue", 123);
string stringValue = (string)hkNew.GetValue("NewStringValue");
hkNew.Close();
			

ASP.NET MVC

Action Results

  1. ViewResult – Represents HTML and markup.
  2. EmptyResult – Represents no result.
  3. RedirectResult – Represents a redirection to a new URL.
  4. JsonResult – Represents a JavaScript Object Notation result that can be used in an AJAX application.
  5. JavaScriptResult – Represents a JavaScript script.
  6. ContentResult – Represents a text result.
  7. FileContentResult – Represents a downloadable file (with the binary content).
  8. FilePathResult – Represents a downloadable file (with a path).
  9. FileStreamResult – Represents a downloadable file (with a file stream).
All of these action results inherit from the base ActionResult class.
  1. View – Returns a ViewResult action result.
  2. Redirect – Returns a RedirectResult action result.
  3. RedirectToAction – Returns a RedirectToRouteResult action result.
  4. RedirectToRoute – Returns a RedirectToRouteResult action result.
  5. Json – Returns a JsonResult action result.
  6. JavaScriptResult – Returns a JavaScriptResult.
  7. Content – Returns a ContentResult action result.
  8. File – Returns a FileContentResult, FilePathResult, or FileStreamResult depending on the parameters passed to the method.

Visual Studio 2008

Misc.

  • VS 2008 can target .net 2.0, 3.0, or 3.5

Javascript

== vs === (and !==)

The main difference between these operators is that the == and != will use type coercion when the operands are of different type. If both operands have the same type, then they both work the same way.
                
0 == ''; //true
'' == '0'; //false
0 === ''; //false
'' === '0'; //false


0 == '0'; //true
0 === '0';//false
                
            

Reserved Words

abstract
boolean break byte
case catch char class const continue
debugger default delete do double
else enum export extends
false final finally float for function
goto
if implements import in instanceof int interface
long
native new null
package private protected public
return
short static super switch synchronized
this throw throws transient true try typeof
var volatile void
while with
            

Numbers

  • JavaScript has a single number type - represented as 64-bit floating point
  • 1 and 1.0 are the same value
  • The value NaN is a number value that is the result of an operation that cannot produce a normal result. NaN is not equal to any value, including itself. You can detect NaN with the isNaN( number ) function.
  • The value Infinity represents all values greater than 1.79769313486231570e+308.
  • Math.floor( number ) method can be used to convert a number into an integer

Strings

  • All characters in JavaScript are 16 bits wide
  • JavaScript does not have a character type. To represent a character, make a string with just one character in it.
  • The \u convention allows for specifying character code points numerically. "A" === "\u0041"

Statements

Falsy values
  • false
  • null
  • undefined
  • The empty string ''
  • The number 0
  • The number NaN
Truthy values
  • true
  • the string 'false'
  • all objects

Objects and Object Literals

  • Objects are passed around by reference. They are never copied
Object Literals
A property's name can be any string, including the empty string. The quotes around a property's name in an object literal are optional if the name would be a legal JavaScript name and not a reserved word. So quotes are required around "first-name", but are optional around first_name.
var empty_object = {};

var person = {
    "first-name": "John",
    "last-name": "Smith"
};

person["first-name"]  //John


var flight = {
    airline: "Oceanic",
    number: 815,
    departure: {
        IATA: "SYD",
        time: "2004-09-22 14:55",
        city: "Sydney"
    },
    arrival: {
        IATA: "LAX",
        time: "2004-09-23 10:42",
        city: "Los Angeles"
    }
};

flight.departure.IATA    // "SYD"
            
The undefined value is produced if an attempt is made to retrieve a nonexistent member:
stooge["middle-name"] // undefined
If the object does not already have that property name, the object is augmented:
person['middle-name'] = 'Bob';

References