C# Fundamentals
# Syntactically very similar to Java and C++
# Here is Microsoft's list of selling points:
* Automatic memory management
* No pointers required
* C# has formal syntactic constructs for enumerations, structures, and class properties
* C# allows you to overload operators on your custom types
* C# allows for the declaration of methods that take a varying number of arguments (via parameter arrays)
* C# supports the notion of formal class properties
# Biggest benefit for us:
* C# is ready to be compiled straight into MSIL!
* In order to compile a language like C++ or Java, you must first ensure that you are conforming to proper .NET format (using the common class system, etc.)
* This usually means using a modified version of the language you are used to. C++ has MC++, VB has VB .NET, etc.
The Basics ... Compile Time
* When C# (or any other .NET-friendly language) is compiled, the source code is transformed into an "Assembly"
* Assemblies are the .NET binaries, comprised of Metadata and the platform-independent Microsoft intermediate language (MSIL or CIL)
* MSIL is very similar to Java byte code
* The code remains as MSIL until a block of it is required by the Common Language Runtime (CLR)
* The assemblies themselves are also described using metadata. The description is termed a manifest
* The manifest holds:
o Information about the current version of the assembly
o Culture information (used for localizing string and image resources)
o A list of all externally referenced assemblies that are required for proper execution
* When more than one language has been compiled, there are multiple binaries, each of which is called a module
* Here is an example of a standard C# program:
using System;
//Here is a simple calculator that can do addition
namespace Calculator
{
public class CalcApp
{
public static void Main()
{
Calc c = new Calc();
int ans = c.Add(10,84);
Console.WriteLine("10 + 84 is {0}.", ans);
Console.ReadLine();
}
}
public class Calc
{
public int Add(int x, int y)
{ return x + y; }
}
}
* Here is the Add() method after the C# compiler has turned it into MSIL:
.method public hidebysig instance int32 Add(int32 x, int32y) cil managed
{
// Code size 8(0x8)
.maxstack 2
.locals init ([0] int 32 CS$00000003$0000000)
IL_0000: ldarg.1
IL_0001: ldarg.2
IL_0002: add
IL_0003: stloc.0
IL_0004: br.s IL_0006
IL_0006: ldloc.0
IL_0007: ret
} // end of method Calc::Add
* Can we make sense of this?
* For a comparison, look at the same method in VB .NET and its translation to MSIL:
Class Calc
Public Function Add(ByVal x As Integer, ByVal y As Integer) As Integer
Return x + y
End Function
End Class
* ... and its MSIL:
.method public instance int32 Add(int32 x, int32y) cil managed
{
// Code size 9(0x9)
.maxstack 2
.locals init ([0] int 32 Add)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: add.ovf
IL_0004: stloc.0
IL_0005: br.s IL_0007
IL_0007: ldloc.0
IL_0008: ret
} // end of method Calc::Add
The Basics ... Run Time
# The MSIL is transformed into meaningful CPU instructions by a just-in-time compiler (JIT or "Jitter")
* The Jitter is really a misnomer, because it doesn't do any compiling
* The Jitter actually transforms the MSIL (which is a 3 address logic) into object code that runs native on the machine (therefore it runs nearly as fast as the native code)
* Instead of having an interpreter that may be very slow (like Java does), .NET uses the Jitter to transfor the MSIL into object code in O(N) time (one pass through the code)
* The end result is only a small loss in performance during compiling (because the Jitter can't do phase 4 optimization)
# The CLR uses a different Jitter depending on the platform it is targeting
# Each Jitter is optimized to take full advantage of the specifications of the specific platform
# The CPU instructions are cached on the target CPU so the code can be reused
C# Specifics
* Program logic must be contained within a type definition
* Therefore, there are no global variables or functions
* Here is a simple Hello World application in C#
namespace HelloWorld{
using System;
class Test {
static void Main(){
Console.WriteLine ("Hello World!");
}
}
}
* Note that Main() has to be associated with a type (typically a class) and must be declared static
* The "use" command tells the CLR to look in the specified namespace for any unknown keywords
* The advantage to using namespaces is that they are language-independent
* This language-indpendence allows any programmer using a .NET compliant language to use the same namespaces and the same types as a C# developer.
* For example, here is the same "Hello World" application in VB .NET and MC++ (the .NET compiant version of C++)
' Hello World in VB .NET
Imports System
Public Module MyApp
Sub Main()
Console.WriteLine("Hello World")
End Sub
End Module
//Hello World in MC++
#using <mscorlib.dll>
using namespace System;
void main()
{
Console::WriteLine (S"Hello World");
}
* C# Objects:
o All C# types (including primitive types) derive from a single base type
o This means that all types (vars, structs, array, etc.) share the same basic functionality (they can be converted to a string, serialized, etc.)
o For example, you can apply a string operation to a primitive integer:
int i = 3;
string s = i.ToString();
o C# is type safe, meaning that a variable can be accessed only through the type associated with that variable
o It is not possible to allocate a class type on the stack, so you cannot use a class variable that has not been "new-ed"
* C# Pointers:
o The CLR performs "automatic memory management," so you don't have to worry about dangling pointers, memory leaks, or coping with circular references
o C# does not get rid of pointers ... it just makes them unnecessary for most programming tasks
o Pointers can be used, but they are only permitted in "unsafe" blocks that require high security permission to execute
o Here is an example of pointer use in an unsafe block:
using System;
struct Test {
int x;
unsafe static void Main(){
Test test = new Test();
Test * p = &test;
p->x = 9;
System.Console.WriteLine(test.x);
}
}
C# Odds and Ends
* Inheritence works much like it does in C++
class Location { // Implicitly inherits from object
string name;
// Here is the constructor for Location
public Location (string name){
this.name = name;
}
public string Name {get {return name;}}
public void Display() {
Console.WriteLine(Name);
}
}
* Class URL will now inherit from class Location ...
class URL : Location { // Inherit from Location
public void Navigate(){
Console.WriteLine ("Navigating to " + Name);
}
// Here is the constructor for URL, which calls Location's constructor
public URL(string name) : base(name){}
}
* In C#, you also have the added ability to use the "sealed" keyword
* Using "Sealed" will prevent a derived class from overriding the behavior of the sealed method or class
o Here is how you would seal a class:
sealed class Location { ... }
o Here is how you would seal a method:
public sealed void MyDisplay() { ... } |