Resources
What | Type | Link |
---|---|---|
My .NET Cheatsheet | Cheatsheet | Link |
Interactive learning tutorials | Guide | LearnCS.org |
C# Net-Tutorial | Guide | Link |
C# Quick Guide and Full Guide | Guide | TutorialsPoint |
C# Tutorials | Guide | TutorialsTeacher.com |
Fundamentals of Computer Programming with C# (by Svetlin Nakov) | Ebook | PDF Ebook |
Learn C# Basics in 1 Hour (Programming with Mosh) (YT) | Video Tutorial | YouTube |
CLR?
Like Java, C# is not compiled straight to assembly / machine / native code - instead it is compiled to CIL (Common Intermediate Language) code, aka bytecode, which is portable across environments. The CLR (Common Language Runtime) is what handles converting / compiling this IL code into actual machine code for each device.
Similarly, Java compiles to Java Bytecode, which is loaded and executed on the Java Runtime Environment (JRE).
Built-in Types
C# Type Alias | .NET Type | Subset type | Description | Size (bits) | Range | Default |
---|---|---|---|---|---|---|
object | System.Object | reference | Object - the ultimate base class | NA | NA | null |
string | System.String | reference | Represents a sequence of zero or more Unicode characters (Char) | NA | NA | null |
bool | System.Boolean | bool | Boolean (true / false) | 8 | True | False |
char | System.Char | char | 16-bit Unicode character holder | 16 | U+0000 to U+FFFF | \0' (U+0000) |
byte | System.Byte | integral numeric | 8-bit unsigned integer | 8 | 0 to 255 | 0 |
sbyte | System.SByte | integral numeric | 8-bit signed integer | 8 | -128 to 127 | 0 |
short | System.Int16 | integral numeric | 16-bit signed integer | 16 | -32,768 to 32,767 | 0 |
ushort | System.UInt16 | integral numeric | 16-bit unsigned integer | 16 | 0 to 65,535 | 0 |
int | System.Int32 | integral numeric | 32-bit signed integer | 32 | -2,147,483,648 to 2,147,483,647 | 0 |
uint | System.UInt32 | integral numeric | 32-bit unsigned integer | 32 | 0 to 4,294,967,295 | 0 |
long | System.Int64 | integral numeric | 64-bit signed integer | 64 | -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 | 0 |
ulong | System.UInt64 | integral numeric | 64-bit unsigned integer | 64 | 0 to 18,446,744,073,709,551,615 | 0 |
float | System.Single | floating-point numeric | Single-precision float | 32 | ±1.5 x 10-45 to ±3.4 x 1038 | 0 |
double | System.Double | floating-point numeric | Double-precision float | 64 | ±5.0 × 10-324 to ±1.7 × 10308 | 0 |
decimal | System.Decimal | floating-point numeric | High-precision float (fractional), that can represent up to 29 significant digits | 128 | ±1.0 x 10-28 to ±7.9228 x 1028 | 0 |
What's with...
- The brackets above methods?
[HttpGet]
, etc.- Those are Attributes, which are a way to inject metadata into the code which can be read during runtime
- The process by which these attributes, or built-in metadata, is read during runtime is called reflection
- Those are Attributes, which are a way to inject metadata into the code which can be read during runtime
- The braces at the end of members?
- Check out the
properties
andaccessors
section
- Check out the
- The
Type<...>
, a type followed by angle brackets (aka less than and greater than) enclosing another type?- See
generics
- See
Properties and accessors
Members on a class in C# are generally called fields
. A property
is just a field
(again, a class member), that has special logic for reads and/or writes to the field. The difference between many other approaches and C#'s here, is that C# lets you basically define the methods for get
and set
directly on the member, without requiring making it a private member, or declaring the methods separately.
The reasoning behind this and why the docs recommend using them is twofold:
- If you a make a member field public, then the integrity of its value cannot always be ensured
- A regular member cannot invoke logic before returning
- PS: This reason is the same reason why a lot of frameworks have something they called
computed properties
With a property, you have two options for defining the get
and set
'ers.
Option A: Use a private member, aka a backing field as storage
This is a very common code pattern. You define a private member in your class, and then expose the methods to retrieve or set that field with custom getters / setters. Here's an example:
public class User
{
private int _age;
public int Age
{
get
{
return this._age;
}
set
{
if (value > 0){
this._age = value;
}
}
}
}
Within the context of C#, the private member is often called a backing field
or the storage
for the public methods.
You can make a property read-only by simply not defining a set method, or write-only by not defining a get method :)
Option B: Automatic properties
In C# v3.0+, you can use what they call auto-implemented
properties; basically, if you want a property that gets and sets with no extra logic (getting it returns the value, setting it sets the value to what was passed), you can have the compiler automatically implement that boilerplate for you:
public class User {
public int Age {get; set;}
}
The compiler does a few things upon seeing this:
- Creates a private member backing field
- Hooks up the get and set logic
You might be wondering why not just use a field (public member) if
get
andset
doesn't do anything special and is auto-generated. The answer has more to do with what other code is expecting. For example,data binding
in C# expects properties, not fields, in order to work. There are other reasons as well - see this.
Another benefit here is that you can even have it generate a private setter; that will make it so you can only set the value of the variable from inside the class, not outside:
public class User {
public int Age {get; private set;}
}
Generics
You will often see something in C# that looks like this:
User<Senior> myUser = new User<Senior>("John");
This is an example of the use of generics
, where is a way for classes and/or methods to accept multiple types in the same parameter. In this case, the User
class might look like this:
public class User<T> {
public string getAgeRange(T userAgeBracket){
// ...
}
}
In this case, the User
class accepts the "age bracket" of the user (child, adult, senior), which is another class/type, as a generic type property, T
. When we instantiate the User class, we pass in the specific type for T
, within the angle brackets, and the compiler replaces the instances of T
with Senior
.
More reading: MSDocs, TutorialsTeacher