When you compile C# is compiles to IL Code (Intermediate Language). CLR then takes the IL code into machine code using Just In Time compilation. That means you can write the program on Mac, then take the IL and run it on Windows
A collection of Classes that are related to each other
- Database
- Storage
- etc
A collection of Namespaces, such as a DLL or EXE
These are the common primitive types:
- byte
- short (2 bytes)
- int (4 bytes)
- long (8 bytes)
- float (4 bytes)
- double (8 bytes)
- decimal (16 bytes)
- char (2 bytes)
- bool
- stored on the stack
- all primitive types, plus the struct type
- short lifespan. As soon as they go out of scope they are destroyed
- stored in the heap
- any classes (Object, Array, String, Vehicle)
- have a performance penalty
- the process of converting a value type instance to an object reference
int number = 10;
object obj = number;
- here the number is "boxed" in an object and is stored on the heap
- opposite of boxing
- a new variable on the stack is created
object obj = 10;
int number = (int)obj;
Using var
to declare variables lets C# detect the data type itself
char character = 'A';
var character = 'A';
NOTE that C# defaults to:
- int for intergers
- float for real numbers
- % gives the remainder after division e.g.
a % b
- postfix increment:
int a = 1; int b = a++;
gives a = 2 and b = 1 - prefix increment:
int a = 1; int b = ++a;
gives a = 2 and b = 2 - multiplication assignment:
a *= 3
(a = a * 3) - division assignment:
a /= 3
(a = a / 3) - NOTE: dividing 2 integers will result in an integer! You need to cast each variable to a float in order to get a float result:
int a = 10;
int b = 3;
Console.WriteLine(a / b); // Results in "3"
Console.WriteLine( (float(a) / float(b))); // Results in "3.3333333"
By default there is no overflow protection. A byte variable with value 255 will overflow to 0 if it is incremented. To prevent this use the checked
keyword to throw an exception if an overflow is detected:
checked
{
byte number = 255;
number++;
}
Contain Fields and Methods Objects are instances of Classes
public class Person
{
// Fields: Variable declarations for the class
public string Name;
// Methods: Functions to operate on the class
public void Introduce()
{
Console.WriteLine("Hi, my name is" + Name);
}
}
Person person = new Person(); # Need to allocate memory to the Object # Garbage Collection removes all objects that aren't used, so don't need to get rid of them
var person = new Person();
person.Name = "Mark";
person.Introduce();
static int Add(int a, int b) {return (a + b)}
- when we add "static" to a Method it means we can access the method through the class that holds the method. We DONT have to create an object first
- we CANNOT access static methods from objects. ONLY from the Class
- without the static modifier, each object in memory has a copy of each method
- with the static modified, there can only be a single instance of a method in memory
- accessible from an object
var person = new Person();
person.Introduce(); // Introduce is an Instance class member
- accessible from the class directly
- used to represent concepts that are singleton e.g. there should only be one of these in the program
Console.WriteLine(); // WriteLine is a static class member
DateTime.Now // Now is a static class member
- has the same name as the class
- has initialisation code for the class
- no return type
- can pass in variables
- the compiler creates a default constructor if you don't specify one
- if you overload the constructor with custom constructors, the compiler doesn't create a default anymore, so you need to define one
- type 'ctor' as a shortcode for creating a constructor
- ALWAYS initialise a list field to an empty list
- overloading makes constructing easier
public class Customer
{
public Customer() { ... }
public Customer(string name) { ... }
public Customer(int id, string name) { ... }
}
- use : this() on the constructor declaration to reference higher level constructors and avoid having to duplicate code:
- BEST PRACTICE: only use constructors when a field REALLY needs to be initialised to avoid future exceptions e.g. creating a list in the object fields.
public Customer()
{
Orders = new List<Order>();
}
public Customer(int id)
: this() // References Customer()
{
this.Id = id;
}
public Customer(int id, string name)
: this(id) // References Customer(int id)
{
this.Name = name;
}
- a syntax for quickly initialising an object without the need to call one of its constructors
- avoids needing to create multiple constructors
- the default constructor is called, THEN the object initialisation code is used
- example of an initialiser is as follows:
var person = new Person {
FirstName = "Mark",
LastName = "Bradshaw"
};
- name
- number and type of parameters
- having a method with the same name but different signatures
- a method can have a varying number of parameters:
public int Add(int[] numbers) {}
- this isn't great though as you need to declare an array every time you call the Method
- gets over the problem highlighted above
public int Add(params int[] numbers) {}
- can then call this with
var result = calculator.Add(1,2,3,4);
public void DoAWeirdThing(ref int a)
{
a += 2;
}
var a = 1;
weirdo.DoAWeirdThing(ref a);
- changes the parameter to a REFERENCE instead of a copy. 'a' will be modified here
- this is against the way things work in C#
public void MyMethod (out int result)
{
result = 1;
}
int a;
myClass.MyTheod(out a);
- let's you return values through the result
- note that the method is a 'void'
- breaks the convention of using a return type and a specific
return
code
- modify the implementation of an inherited method
- checkout "BadShapeImplementation" and "GoodShapeImplementation" for an example
- use
virtual
in the declaration of the base class method - use
override
in the declaration of the sub class method
public class Shape
{
public virtual void Draw() { // Default implementation }
}
public class Circle : Shape
{
public override void Draw() { // New implementation }
}
- preferred way to initialise is like this, creating and assigning the field in one go instead of definiing the field as
List<Order> Orders
then relying on the constructor to assign a new List to it. - note that some developers don't like this approach and prefer to rely on the constructor
public class Customer
{
List<Order> Orders = new List<Order>();
}
- must be assigned within the constructor method
- can only be initialised once. In this example once Orders has been declared it can't be declared again later. Avoids the possibility of a bug causing data loss
public class Customer
{
readonly List<Order> Orders = new List<Order>();
}
- a way to control access to a class and/or its members
- accessible from everywhere
- accessible only from the class
- accessible only from the class and its derived classes
- similar to "private"
- sometimes considered bad practice as exposes internal workings to other classes
- accessible only from the same asssembly
- e.g. make a class available to other classes in an assembly
- accessible only from the same assembly or any derived classes
- BAD practice!
- indicates that a class or a member is missing implementation
- inherently 'virtual'
public abstract class Shape
{
public abstract void Draw();
}
- if you declare a method as 'abstract' then the class needs to be declared 'abstract' as well
- a member class MUST implement ALL abstract methods in the base abstract class
- abstract classes CANNOT be instantiated
var shape = new Shape(); // won't compile
- when you want to provide some common behavious, while forcing other developers to follow your design
- e.g. example for Shape above FORCES another developer to implement the Draw method for their member class
- applied tp a class or class member
- opposite of abstract
- prevents derivation of classes or overriding of methods
public sealed class Circle : Shape { ... }
public sealed override void Draw() { ... }
- sealed classes are slightly faster because of some run-time optimisations
- very rarely used, possibly an anti-pattern
- hide fields that do not need to be available externally
- private fields should start with an underscore as shown below
- provide getter/setter methods as public to manipulate the fields
public class Person
{
private string _name;
public void SetName(string name) {
if (!String.IsNullOrEmpty(name))
this._name = name;
}
public string GetName()
{
return _name;
}
}
- a class member that encapsulates a getter/setter for accessing a field
private DateTime _birthdate;
public DateTime Birthdate
{
get { return _birthdate; }
set { _birthdate = value; }
}
- compiler recognises this special case and creates the field for you
public class Person
{
public DateTime Birthdate { get; set; }
}
### Viewing partially compiled code
- on Windows,
ildasm
- on Mac, use either
monodis
orikdasm
- a way to access elements in a class that represents a list of values
cookie["name"] = "Mark"; // Using an indexer
cookie.SetItem("name", "Mark"); // Same code but not using an indexer
var name = cookie["name"]; // Using an indexer
var name = cookie.GetItem("name"); // Same code but not using an indexer
- it is basically a property:
public class HttpCookie
{
public string this[string key] // use "this" keyword
{
get { ... }
set { ... }
}
}
- this is BAD
- it is when a change in one class affects a large number of interlinked classes
- a minor class change can have a major application change
- this is GOOD
- changing a class affects only that class
- no class should know about the implementation of another class
- important: encapsulation, relationship between classes, interfaces
- Is-a relationship
- PROs: Code re-use, easier to understand
- CONs: tightly coupled, fragile, can be abused
public class PresentationObject
{
// Common shared code
}
public class Text : PresentationObject
{
// Code Specific to Text
}
- base class constructors are executed first
- base class constructors are not inherited
public class Vehicle
{
private string _registrationNumber;
public Vehicle(string registrationNumber)
{
_registrationNumber = registrationNumber;
}
}
public class Car : Vehicle
{
public Car(string registrationNumber)
: base(registrationNumber)
{
// initialise fields specific to the Car class
}
}
- if the constructor of the base class needs a parameter, you need to deal with this in your sub class as well
- :base lets you access the base contructor class
- conversion from a derived class to a base class
public class Shape { }
public class Circle : Shape { }
Circle circle = new Circle();
Shape shape = circle; // Upcasting. No conversion is required. Upcasting is implicit
Circle anotherCircle = (Circle)shape; // Downcasting. Explicit cast required
-
will get an InvalidCastException if you try to explicit cast to a different class
-
in the example above, both "shape" and "circle" point to the same object but present different views of it
-
Downcasting is frequently needed when using libraries as the types can be set to "object". Downcast to the type you need so you can access Methods you need
- prevents exceptions when the cast can't be done
- use this when you're not sure what the runtime class of an object is going to be
Car car = (Car) obj; // Can throw an exception in this explicit cast
Car car = obj as Car; // Safer. Will return null if fails
if (car != null) { ... }
- test if an object is a particular class
if (obj is Car) { ... }
- a kind of relationship between 2 classes that allows one to contain the other
- Has-a relationship
- PROs: code re-use, great flexibility, loose coupling
- CONs: harder to understand
- Example: Car has an Engine
- Example: many classes need a way to log information.
- DBMigrator --> Logger
- Installer --> Logger
public class Installer
{
private Logger _logger;
public Installer(Logger logger)
{
_logger = logger;
}
}
## Composition over Inheritance
- Problems with inheritance
- easily abused by amataur designers / developers
- leads to large hierarchives
- fagility
- tight coupling
- Composition
- any inheritance relationship can be modelled with Composition
- great flexibility
- eventually loose coupling
- Inheritance is not necessarily a bad thing
- Use both inheritance and composition
- Similar to a class in syntax, but is fundamentally different
- interface members don't have implementations, just definitions
- interface members don't have modifiers (e.g. public, private, etc)
- used for building extensible, testable and loosely coupled applications
public interface ITaxCalculator
{
int Calculate();
}
- useful to define classes that you haven't implemented yet
Small difference between a struct and a class. Structs are lighter, so if you are declaring thousands of them then structs will be more efficient
public struct RgbColour
{
public int Red;
public int Green;
public int Blue;
}
- a way of storing data in a key, pair combination (e.g. like a map in Go)
- use a List<> for an ordered list of items
- Arrays are classes
- Arrays have a fixed size, and need memory to be allocated to them:
int[] numbers = new int[3];
numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 3;
or:
int[] numbers = new int[3] { 1, 2, 3 };
Two types:
- rectangular: each row has the same number of columns
- jagged: number of columns can be different for each row. An array of arrays
var matrix = new int[<ROW>, <COLUMN>];
var matrix = new int[3, 5];
var matrixValues = new int[3, 5]
{
{ 1, 2, 3, 4, 5 },
{ 6, 7, 8, 9, 10 },
{ 11, 12, 13, 14, 15}
};
var element = matrixValues[0, 0];
// 3 dimensional array
var colours = new int[3, 5, 4];
We don't declare the size of the column (second element)
var array = new int[3][]; // Leave the second element empty
array[0] = new int[4];
array[1] = new int[5];
array[2] = new int[3];
array[0][0] = 1;
Field: Length Methods:
- Clear()
- Copy()
- IndexOf()
- Reverse()
- Sort()
- Similar to arrays, but have a dynamic size
- MOst of the time we use Lists instead of Arrays
var numbers = new List<int>(); // int specifies the type of the list
var numbers = new List<int>() { 1, 2, 3, 4 };
- can create a list of any type, including userdefined types
- Methods:
- Add()
- AddRange()
- Remove() # Note: we can't remove elements in a foreach loop
- RemoveAt()
- IndexOf()
- Contains()
- Count
- "String" class and "string" type are exactly the same
- strings are classes
- Strings can be concatented. Use the string.Format method as shown to make the output easier to visualise
- Strings are immutable. Once created, they cannot be changed
- All methods that manipulate strings create new strings in the background
- Special characters need to be escaped with "" e.g. "\", "\n", "\t"
string firstName = "mark";
string lastName = "bradshaw";
string name = firstName + " " + lastName;
string otherName = string.Format("{0} {1}", firstName, lastName);
var numbers = new int[3] { 1, 2, 3};
string list = string.Join(",", numbers);
string name = "Mark";
char firstChar = name[0]; // Will be set to 'M'
- no need to escape special characters
string path1 = "c:\\projects\\project1\\folder1";
string path2 = @"c:\projects\project1\folder1";
- ToLower() # Returns lower case string
- ToUpper() # Returns upper case string
- Trim() # Removes whitespace
- IndexOf('a') # Searches the string for the first occurrance of 'a'
- LastIndexOf("Hello") # Searches the string for the last occurrance of "Hello"
- Substring(startIndex) # From startIndex to end of string
- Substring(startIndex, length) # From startIndex for amount of length
- Replace('a', '!') # Replace single character
- Replace('mark', 'marky') # Replace entire string
- String.IsNullOrEmpty(str)
- String.IsNullOrWhiteSpace(str)
- String.Join(" ", words) # Joins the strings in the list words using " " as deliminator
- str.Split(' ') # Split string by space
- int i = int.Parse(str) # Convert string to integer. Exception on null string
- int j = Convert.ToInt32(str) # Does the same thing: covert string to integer. Safer
- Coverting numbers to strings:
int i = 1234;
string s = i.ToString(); // "1234"
string t = i.ToString("C"); // "$1,234.00"
string t = i.ToString("C0"); // "$1,234"
Each format string can take a number after it to signify number of places
- c or C: Currency 123456(C) -> $123,456
- d or D: Decimal 1234(D6) -> 001234
- e or E: Exponential 1052.0329112756(E) -> 1.052033E+003
- f or F: Fixed Point 1234.567(F1) -> 1234.5
- x or X: Hexadecimal 255(X) -> FF
using System.Text
- optimised for string manipulation
- not for searching so can't find substrings inside a start string
- no methods for IndexOf, LastIndexOf, Contains, StartsWith
- includes Append, Insert, Remove, Replace, Clear
- can still index individual characters
myString[0]
- can chain methods together e.g.
var myString = new StringBuilder();
myString
.Append('-', 10)
.AppendLine()
.Append("Header")
.AppendLine()
.Append('-', 10)
.Replace('-', '+')
.Insert(0, new string('-', 10));
A value type defined by a set of named constants of "int". Instead of multiple contstants e.g.
const int RegularAirMail = 1;
const int RegisteredAirMail = 2;
const int Express = 3;
use an enum covering Shipping Methods:
public enum Shipping Method
{
RegularAirMail = 1,
RegisteredAirMail = 2,
Express = 3;
}
var method = ShippingMethod.Express;
To get user input from the console use Console.ReadLine()
You can collapse cases if the code is the same. In the following example the case for Season.Autumn will fall into the code for Season.Summer:
switch (season)
{
case Season.Autumn:
case Season.Summer:
Console.WriteLine("Sales promotion time!");
break;
default:
Console.WriteLine("Normal pricing");
break;
}
Conditional operator is condition
? : . It is short hand for a simple if..else condition.
bool isGoldCustomer = true;
float price = (isGoldCustomer) ? 19.95f : 29.95f;
- FileInfo: provides instance methods
- faster
- File: provides static methods
- security checks are done every time a static method is used
- if you call static methods many, many times the overhead is significant
- File, FileInfo Methods
- Create()
- Copy()
- Delete()
- Exists()
- GetAttributes()
- Move()
- ReadAllText() # Reads all the text in a file
- Directory, DirectoryInfo
- GetLogicalDrives() # Logical drives of your hard disk (C:, D:, etc)
- GetCurrentDirectory()
- GetFiles() # Can provide filters
- Path
- GetDirectoryName()
- GetFileName()
- GetExtension()
- GetTempPath()
for (var i = 0; i < 10; i++)
{
...
}
Used to iterate over a list, array or string
var name = "John Smith";
foreach (var character in name)
{
...
}
Can be used in the same situations as the for loop, but much better to use it when we don't know how many times round the loop we'll go.
var i = 0;
while (i < 10)
{
...
i++;
}
The loop is executed at least once as the condition is evaluated at the end of the loop
do
{
...
i++;
} while (i < 10);
- break: jumps out of the loop
- continue: jumps to the next iteration of the loop
- a list of Interfaces
- lets you use 1 or more interfaces
public class Video
{
private readonly IList<INotificationChannel> _notificationChannels;
public VideoEncoder()
{
_notificationChannels = new List<INotificationChannel>();
}
public void Encode(Video video)
{
foreach (var channel in _notificationChannels)
channel.Send(new Message());
}
public void RegisterNotificationChannel(INotificationChannel channel)
{
_notificationChannels.Add(channel);
}
}
- See "Polymorphism example" in github
- created to get away from having to create a class for a list of different types OR creating a class for storing "object" which leads to boxing/unboxing
- generics mean that at runtime the lists are actually the defined types instead of being just objects and needing to be boxed/unboxed
- C# has many built in generic types in System and System.Collection.Generic and you'll ususally use one of these instead of create your own generic like the code below
- For example, System.Nullable<>
public class GenericList<T>
{
public void Add(T value)
{
}
public T this[int index]
{
get { throw new }
}
}
var numbers = new GenericList<int>();
numbers.Add(10);
var books = new GenericList<Book>();
books.Add(new Book());
-
an object that knows how to call a method (or a group of methods)
-
a reference (or a pointer) to a function
-
why?
- for designing extensible and flexible applications (e.g. frameworks)
-
code example: delegate project
-
in .NET framework there are 2 delegates that can be used instead of needing a custom delegate: "action" and "func"
- System.Action<> returns void
- System.Func<> returns a value
-
only needed where we need lots of flexibility or extensibility
-
use a delegate when:
- an eventing design pattern is used
- the caller doesn't need to access other properties or methods ont the object implementing the method
- an anonymouse method (no access modifier; no name; no return statement) ## Why do we use them?
- convenience
- makes code more readable
- args "goes to" expression
// args => expression
number => number * number;
// equivalent to:
public int Square(int number)
{
return number * number;
}
- you can also define a delegate using a lambda expression:
Func<int, int> square = number => number * number;
Console.WriteLine("Square of 5 is " + square(5));
- here, Func's parameter types are <input_type, result_type>
- square is the name of the delegate
number => number * number
is what it will do
- no arguments:
() => ...
- one argument:
x => ...
- multiple:
(x, y, z) => ...
- a predicate is a delegate that returns a bool telling you if the condition is satisfied
- can do this using a lambda as well:
var cheapBooks = books.FindAll(book => book.Price < 10);
// Will return all books with a price less than 10
- a mechanism for communicating between objects
- used in building Loosely Coupled Applications
- helps extending applications
- class A is the publisher and sends events. It knows nothing of the subscribers
- class B is the subscriber and receives events
// Subscriber creates an event handler along the following lines:
public void OnVideoEncoded(object source, EventArgs e) { ... }
- delegates are used:
- agreement / contract between Publisher and Subscriber
- determines the signature of the event handler method in Subscriber
- add methods to an existing class without
- changing it's source code
- creating a new class that inherits from it
- use extension methods sparingly
- defnied as static methods but are called by using instance method syntax
- need to add
using System.Linq;
- first parameter specifies which type the method operates on. The parameter is preceded by the "this" modifier
public static class StringExtensions
{
public static string Shorten(this String str, int numberOfWords)
{
...
}
}
...
string post = "Lots and lots of words"
var shortenedPost = post.Shorten(5);
- stands for Language Integrated Query
- Lets you query objects
- objects in memory (LINQ to Objects), databases (LINQ to Entities), XML (LINQ to XML), ADO.NET data sets (LINQ to Data Sets)
- add
using System.Linq
for LINQ
- LINQ expressions can also be chained. Here we'll pull out the cheap books, then sort by title
var cheapBooksLINQ = books.Where(b => b.Price < 10).OrderBy(b => b.Title);
- To order a collection by something, use LINQ with a lamba:
books.OrderBy(b => b.Title);
- To select one of more properties from an object use Select(). Here we just pick the title so the result will be a string
books.OrderBy(b => b.Title).Select(b => b.Title);
- To select a single result:
var book = books.Single(b => b.Title == "ASP.NET MVC");
- Single method expects there to be one and only one result. Otherwise throws an exception
- If you're not sure, use SingleOrDefault:
var book = books.SingleOrDefault(b => b.Title == "ASP.NET MVC++");
// Since this might be null, we check for book being null when printing
// This will print "True" if book is null, otherwise "False"
Console.WriteLine(book == null);
- First() gets the first item found in a list
- Last() gets the last item in a list
var book = books.First(b => b.Title == "C# Advanced Topics");
var book = books.FirstOrDefault(b => b.Title == "C# Advanced Topics");
var book = books.Last(b => b.Title == "C# Advanced Topics");
var book = books.LastOrDefault(b => b.Title == "C# Advanced Topics");
- Skip() skips the number of entries specified
- Take() takes the number of entries specified
// Skip the first 2 entries, then return the next 3
var pagedBooks = books.Skip(2).Take(3);
- Count() counts the number of list entries
- Max() returns the maximum of something. You will have to define what Max means for your list
- Min() returns the minimum of something
// Returns the highest price in the list
var highPrice = books.Max(b => b.Price);
- Sum() returns the sum of all the defined entries
var totalPricing = books.Sum(b => b.Price);
books.Where();
books.Single();
books.SingleOrDefault();
books.First();
books.FirstOrDefault();
books.Last();
books.LastOrDefault();
books.Min();
books.Max();
books.Count();
books.Sum();
books.Average(b => b.Price);
books.Skip(5).Take(3);
## LINQ Query Operators
var cheaperBooks = from b in books
where b.Price < 10
orderby b.Title
select b.Title;
- Value Types cannot be Null
- In some situations you need a null (e.g. Customer.Birthday (datetime NULL))
- Nullable<> is a generic type in the System namespace
Nullable<DateTime> date = null; // Longhand
DateTime? date = null; // Shorthand
- Methods of the Nullable type:
- .GetValueOrDefault - preferred way of getting the value. You either get the value, or you get the default value for the type
- .HasValue - true / false depending on whether there's a set value
- .Value - will get an exception if the value is null
DateTime? date = new DateTime(2014, 1, 1);
DateTime date2 = date.GetValueOrDefault(); // Need to set to value to get away from Nullable
DateTime? date3 = date2; // This is fine. No need for a cast
if (date != null)
date2 = date.GetValueOrDefault();
else
date2 = DateTime.Today;
Can be replaced by the null coalescing operator:
DateTime date2 = date ?? DateTime.Today;
- means: if date is not null set date2 = date. If date is null then set date2 = DateTime.Today
- Similar approach to tertiary operator:
DateTime date3 = (date != null) ? date.GetValueOrDefault() : DateTime.Today;
-
Statically-typed languages: C#, Java (type resolution is done at compile time)
- PRO: early feedback
-
Dynamically-typed languages: Ruby, Javascript, Python (type resolution at run time)
- easier and faster to code
-
.NET 4 added the dynamic capability to improve interoperability with:
- COM (e.g. writing office applications)
- Dynamic Languages in .NET (IronPython)
dynamic excelObject = "Mark";
excelObject.Optimize();
dynamic name = "Mark";
name = 10; // This is fine. The type of "name" changes as it is assinged to
dynamic a = 10;
dynamic b = 5;
var c = a + b; // c will end up dynamic because a and b are also dynamic
- type casts happen automatically to dynamic variables, as long as it's implicitly convertable
- we put the code that might throw an exception in a try / catch block
- catch block code runs when an exception occurs in the try block
- in the catch block we have a choice:
- catch the exception and deal with it
- pass the exception to the calling routine
- in general, the main program level should always be inside a try / catch block
- can have multiple catch blocks, going from most to least specific. The order is important
try
{
}
catch (Exception ex)
{
throw;
}
finally
{
}
System.Exception
is the top level type of call exceptions- .Message: the exception text
- .Source: the place where the exception happened
- .StackTrace: the stack trace up to when the exception happened
- .TargetSite: The exact place where the exception happened
finally
block- used to manually do a clean-up of unmanaged resources
IDisposable
disposes of these e.g. a StreamReader to close open files
using
statement negates the need for afinally
block:
try
{
using (var streamReader = new StreamReader(@"c:\file.zip"))
{
var content = streamReader.ReadToEnd();
}
}
catch (Exception ex)
...
- create a class that derives from Exception:
- just need to pass the message and exception to the base
public class YouTubeException : Exception
{
public YoutubeException(string message, Exception innerException)
: base(message, innerException)
{
...
}
}
// To use this can call YouTubeException:
throw new YouTubeException("Could not fetch videos from YouTube", ex);
## Stack Trace A stack trace shows the history of calls that happened before the exception, in reverse order. The stack trace is show along with the exception.
- when a function is called, program execution continues to the next line, without waiting for the function to complete
- improves responsiveness of application
- use it anytime we have a blocking operation (e.g. reading from the network)
- since .NET 4.5 we use Async/Await
- the following line uses an Async version of DownloadString to carry out the action in the background. The "await" tells the compiler to come back here once the operation has completed so that code after it can be run
- we can only use the await modifier in an async method
public async Task DownloadHtmlAsync(string url)
{
var html = await webClient.DownloadStringTaskAsync(url);
}
// Another example:
public async Task<string> GetHtmlAsync(string html)
{
var WebClient = new WebClient();
return await webClient.DownloadStringTaskAsync(url);
}
// Here a message is printed after the task is setup but before it runs
// Uses multi-threading to improve responsiveness
var getHtmlTask = GetHtmlAsync("http://docs.microsoft.com");
Console.WriteLine("We're downloading things from microsoft"); // Runs immediately
var html = await getHtmlTask; // At this point the control is passed pack to the main program until the download is complete
Console.WriteLine(html.Substring(0, 10));
- executed line by line one at a time
- when a function is called, program execution has to wait until the function returns
Used to interact with the console
- Console.WriteLine("x"); # Prints "x" to the Console
A collection of conversion methods for changing variable types
- Convert.ToInt32(s);
- DateTime objects are immutable. Once they are set they cannot be changed
- DateTime.Now # The time now
- DateTime.Today # Today's date
var now = DateTime.Now;
var today = DateTime.Today;
Console.WriteLine("Hour: " + now.Hour);
Console.WriteLine("Minute: " + now.Minute);
- there are many methods beginning with "Add" which change the dates
var tomorrow = now.AddDays(1);
var yesterday = now.AddDays(-1);
Console.WriteLine(now.ToLongDateString()); // Long format, date only
Console.WriteLine(now.ToShortDateString()); // Short format, date only
Console.WriteLine(now.ToLongTimeString()); // Long format, time only
Console.WriteLine(now.ToShortTimeString()); // Short format, time only
Console.WriteLine(now.ToString("yyyy-MM-dd")); // Convert the date to a string, with format
var timeSpan = new TimeSpan(1, 2, 3); // One hour, two minutes, three seconds
var timeSpan1 = new TimeSpan(1, 0, 0); // Specify only one hour
It's not clear what these numbers mean. TimeSpan has methods for clarity
var timeSpan2 = TimeSpan.FromHours(1); // same as timeSpan1 definition
Working with TimeSpan:
var start = DateTime.Now;
var end = DateTime.Now.AddMinutes(2);
var duration = end - start;
Console.WriteLine("Duration: " + duration);
random.Next();
- returns a non-negative random number
random.Next(minValue, maxValue)
- random numbers between minValue and maxValue
- can use this to generate random characters by casting to char:
var random = new Random();
Console.WriteLine("Random character: " + (char)random.Next((int)'a', (int)'z'));
Console.WriteLine("Random character: " + (char)('a' + random.Next(0, 26)));
- CMD-click on a type, method or class brings up the Assembly Browser so you can look through the available methods
- type cw will fill in Console.WriteLine()