Reinventing The Wheel

.Net Facts

On this page you'll find a bunch of random but interesting facts to do with C# and .NET in general.

Difference Between Int32 and int

"Int32" is a .NET class and can be used in any .NET language, eg. "Int32 x = 10;"
"int" however, is specific to C# (and probably other .NET languages) and maps directly to "Int32".
There is no difference between using one or the other (except for one situation, see the next section below for more info).
"Int32 x = new Int32();" is exactly the same as "int x";
Using the "new" operator does not assign memory on the heap, and it doesn't box the int.

Below is a table showing the C# key word and the corresponding type in .NET:

C# Key Word .NET Type
bool Boolean
byte Byte
char Char
decimal Decimal
double Double
float Single
int Int32
long Int64
sbyte SByte
short Int16
uint UInt32
ulong UInt64
ushort UInt16

The C# key words short, int and long were obviously chosen due to their bit lengths (16, 32 and 64).

Int32 vs int

Int32 and int can be used in place of each other in every situation, except when using it as the backing type for an enum.

An enum's backing type can be any integral type (except Char), and is by default Int32.

However, if you felt the need to explicitly declare the backing type as Int32, you have to use the keyword int.

The reason for this is because Int32 is not a keyword, you could create your own class called Int32, but the enum would not be allowed to derive from this since it wouldn't be an integral type.

So to stop the confusion, the compiler team decided to make you use keywords instead of type names.

Not all classes are reference types

This is because structs and enums are just classes which derive from System.ValueType.

LINQ "Keywords" Are Not Really Keywords

LINQ stands for Language Integrated Query and was introduced in .NET 3.5.
It's basically a way of querying data with a syntax similar to SQL.
An example of a LINQ query expression is given below:
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
var numQuery =
            from num in numbers
            where (num % 2) == 0
            select num;

Although the words "from", "where" and "select" appear to be keywords, they are not.
It is possible to have a variable name "from", "where", or "select". This is because these words are treated as keywords only in a contextual manner.
The compiler looks for the word "from" and knows that this is the start of a LINQ query. So only in the context of a LINQ query are these words treated as keywords.
The reason they decided to design it this way is because before LINQ was introduced, programmers may have been using "from", "where" or "select" as variable names,
and introducing a new feature into C# shouldn't break this.

Why doesn't LINQ use the "select" clause before the "from" clause like in SQL?

There are two reasons why LINQ has the "from" clause before the "select" clause.
1. It lets you use IntelliSense. If the "select" clause was declared first, IntelliSense wouldn't work since the "from" clause tells you about the variable name and type.
2. "from" happens logically first and then "select", not the other way around. Not sure why SQL decided to have it the other way around.

Generics and the challenges on the parser front

If you have:
F(G<A,B>(5));
Does this mean that the user wants to call a method F with two parameters that result from comparing G and A, and B and the constant 5?
Or does it mean call F with the result of calling generic method G using type parameters A and B and an argument of 5?

To test this out, two code segments have been used, the one below compiles without any errors:
class A { }
class B { }

class Program
{
    static void F(int x) { }
    static int G<T, U>(int x) { return x; }

    static void Main(string[] args)
    {
        F(G<A, B>(5));
    }
}

However the code below produces errors:
class Program
{
    void F(bool x, bool y) { }

    static void Main(string[] args)
    {
        int G = 0, A = 1, B = 2;
        F(G<A, B>(5));
    }
}

The errors are:
1. The type or namespace name 'A' could not be found (are you missing a using directive or an assembly reference?)
2. The type or namespace name 'B' could not be found (are you missing a using directive or an assembly reference?)
3. The variable 'G' is not a generic method. If you intended an expression list, use parentheses around the < expression.

So it turns out the expression is interpretted as a generic function call.

You can force the compiler to treat it as a single function call with two parameters by using brackets:
F((G<A), B>(5));

Read section 7.6.4.2 of the C# Specification for more information.

If Statements and Boolean Methods

Be careful when using Boolean returning methods as operands in if statements.
In the example below, the method iWontExecute() will never get executed:
public class BooleanMethods
{
    static void Main(string[] args)
    {
        booleanTest();
        Console.Read();
    }

    static private void booleanTest()
    {
        if (true || iWontExecute())
        {

        }

        if (false && iWontExecute())
        {

        }

        if (false || iWillExecute())
        {

        }

        if (true && iWillExecute())
        {

        }
    }

    static private bool iWontExecute()
    {
        Console.WriteLine("This will not be printed.");
        return true;
    }

    static private bool iWillExecute()
    {
        Console.WriteLine("This will be printed.");
        return true;
    }
}
This is because in the first if statement, the first operand is true.
Since it is using the OR operator, it doesn't matter what the second operand is, the whole expression will evaulate to true.
Similarly in the second if statement, the first operand is false.
Since this is the AND operator, the whole expression will evaulate to false regardless of what the second operand is.

If you want iWontExecute() to execute, you would have to put it as the first operand for the first two if statements.
In the third and fourth if statements, the method iWillExecute() does indeed execute since it's returned value will determine the final evaluation of the if statement.

These days most IDEs such as Visual Studio will provide you with a compile time warning ("Unreachable expression code detected") for the first two if statements.

System.DivideByZeroException

The DivideByZeroException only gets thrown when dividing an integer or decimal number by 0, not a floating-point number.
When a floating-point number is divided by 0, the result is +ve infinity, -ve infinity, or NaN. See DivideByZeroException for more info.

Static Classes

Static classes derive directly from System.Object. It's impossible for a static class to derive from any other class because it wouldn't make any sense. Inheritance applies only to objects, and you can't create an instance of a static class.

A static class, once compiled to IL code, is marked with both "abstract" and "sealed". This makes sense because you can't instantiate an abstract class, and a sealed class cannot be derived.

Overriden Methods and Accessibility

If you override a method, the overriden method must be as restrictive as the parent class, or less restrictive.

The reason for this is, that any derived class can be cast to the parent class. If you then try to call the overriden method on this object which is now cast to the parent class, it wouldn't work which wouldn't make any sense.