Every programming language has an assortment of terms. Here are a few from C# that don't seem to fit elsewhere.
operator
The term "operator" is used to overload a built-in operator or for a user-defined type conversion in a class or a struct. Example (from a msdn page):
class Fraction { int num, den; public Fraction(int num, int den) { this.num = num; this.den = den; } // We overload operator + for the Fraction class public static Fraction operator +(Fraction a, Fraction b) { return new Fraction(a.num * b.den + b.num * a.den, a.den * b.den); } // We overload overload operator * for the Fraction class. public static Fraction operator *(Fraction a, Fraction b) { return new Fraction(a.num * b.num, a.den * b.den); } // We have a user-defined conversion from Fraction to double public static implicit operator double(Fraction f) { return (double) f.num / f.den; } }
new
The operator "new" is used to create objects and invoke constructors. For example:
MyClass M = new MyClass();
can also be used to invoke the constructors for value types, as in
int K = new int(8);
but this is simply equivalent to
int K = 8;
and therefore is not especially useful.
It can also be used to create instances of anonymous types (an advanced topic).
As a keyword, "new" also has other uses.
The new operator cannot be overloaded.
In comparison to C++, there is no "delete" operator in C#. If a value has been allocated on the heap but there is no longer a reference to it, the value will be marked as trash and the garbage-collection system will delete it automatically.
explicit
The keyword "explicit" is used in declaring a user-defined type conversion operator that must be invoked with a cast.
Example (adapted from a MSDN page)
// Convert from a class called Fahrenheit to a class called Celsius: // Must be defined inside a class called Fahrenheit: public static explicit operator Celsius(Fahrenheit fahr) { return new Celsius((5.0f / 9.0f) * (fahr.degrees - 32)); }
This conversion operator can be invoked like this:
Fahrenheit fahr = new Fahrenheit(100.0f); Console.Write("{0} Fahrenheit", fahr.Degrees); Celsius c = (Celsius)fahr; Console.Write("{0} Celsius", c.Degrees);
Here each of the classes Fahrenheit and Celsius has a property called Degrees.
End of Example
The conversion operator converts from a source type to a target type. The source type provides the conversion operator. Explicit conversion operators must be invoked by means of a cast.
Use an explicit conversion operator if the conversion might throw an exception (such as "out of bounds") or lose information.
implicit
The keyword "implicit" is used in declaring a user-defined type conversion operator that can be used implicitly (without a cast).
Use an implicit conversion operator if the conversion is guaranteed not to cause a loss of data.
Example (adapted from a MSDN page)
class Digit { public double val; public Digit(double d) { val = d; } // constructor // ...other members // User-defined conversion from Digit to double public static implicit operator double(Digit d) { return d.val; } // User-defined conversion from double to Digit public static implicit operator Digit(double d) { return new Digit(d); } } class Program { static void Main(string[] args) { Digit dig = new Digit(7); // This call invokes the implicit "double" operator. double num = dig; // This call invokes the implicit "Digit" operator. Digit dig2 = num + 12.0; Console.WriteLine("num = {0} dig2 = {1}", num, dig2.val); Console.ReadLine(); } }
checked and unchecked
These have to do with whether arithmetic operations and conversions of integral types cause overflow. The term "unchecked" is used to suppress overflow-checking, and "checked" is used to switch it on. If neither is used, the behavior depends on compiler options and other external factors.
In a checked environment, overflow will raise an exception (or it may be detected by the compiler if the calculation involves only constants). In an unchecked environment, no exception is thrown. By default, a constant expression involving constant values, as in
int X = 2147483647 + 10; // compile error
is checked, but if it involves values of variables, as in
int Y = 10; int X = 2147483647 + Y; // no compile error; we get X = -2147483639
is not checked.
We can use the keywords to control this:
Console.WriteLine(checked(2147483647 + ten)); .. run-time error
or
int Y = 10; checked { X = 214748647 + Y; } // run-time error
or we could use "unchecked" to avoid the checking; maybe we want the wrap-around behavior in addition.
var
A variable which is local, that is, defined inside a method, may be defined as "var", which has no explicit type until it has a value. For instance:
var I = 10; // I is now an integer.
or
string[] words = { "apple", "strawberry", "grape", "peach", "banana" }; var WordQuery = from word in words where word[0] == 'g' select word;
In the second example, WordQuery will be of type string.
Here we have a "query expression" using "from" and "select". This is an interesting topic; the query expression shown does what it looks like and we will have WordQuery = "grape".
lock
The term "lock" is relevant to multi-threaded programming.
The keyword lock marks a statement block (between braces) as a critical section by obtaining the mutual-exclusion lock for a given object, executing a statement, and then releasing the lock. The following example includes a lock statement.
class Account { decimal balance; private Object thisLock = new Object(); public void Withdraw(decimal amount) { lock (thisLock) { if (amount > balance) { throw new Exception("Insufficient funds"); } balance -= amount; } } }
The keyword lock ensures that one thread does not enter a critical section of code while another thread is in the critical section. If another thread tries to enter a locked code, it will wait, blocked, until the object is released. In the example, notice that thisLock is simply an instance of Object. It could be of any reference type, but it may be best to create a variable just for this purpose with no other references anywhere to the same instance.
in
The key word "in" is used in several situations:
"in" parameters are for input only, not modifiable.
By contrast, "ref" arguments are similar but are modifiable.
Thus we might have:
void F(in char X) // X is passed by reference but // F cannot change the value of X { } void G(ref double Y) // Y is passed by reference and // G may change the value of Y { }
foreach (int M in MyList) { // do something }
It is also used in LINQ when we have join clauses (not an elementary topic) and in "generic interfaces" (also not elementary).
typeof
The keyword "typeof" is used at compile time to get the type of an object, as in:
System.Type type = typeof(int);
Here the Type class contains information about class types, array types, interfaces, enumerations, etc.
To get similar data at runtime, use the GetType method, as in:
int i = 0; System.Type type = i.GetType();
where GetType is a method of the Object class (and therefore is inherited by all others).
as
The keyword "as" is an operator which can perform some kinds of conversions between compatible reference types or nullable types. If the conversion cannot be done, "as" returns null instead of throwing an exception.
A common example would be to convert an instance of a derived class to become an instance of the base class:
Suppose class DEF is derived from class ABC. If Q is an instance of DEF, we could use "as" to recast it as an instance of ABC:
DEF Q = new DEF(); ... R = Q as ABC;
Why would we want to do this? It may be that we want to execute a method of ABC which was overridden in DEF.
is
The keyword "is" is used to evaluate type compatibility at runtime, as in
(expression is type)
which will be true if the "expression" is non-null and its value can be converted to "type".
if (OBJ is Person) { // Do something if OBJ is a Person. }
This can also be used if "type" is an interface: is the value of "expression" of a type satisfying this interface?
if (MyExpression is IComparable) { // presumably we can sort something }
Leftover terms
The following terms should normally be used only in an unsafe context: "unsafe" (to establish the unsafe context), "fixed", "stackalloc", "sizeof" (other than for built-in types). (We should probably try to avoid unsafe contexts.)
These last few may be added later if it is practical. Some are more important than others.