Lecture 3

Here are notes about the topics we covered in lecture 3. For more details on anything below, see the Essential C# textbook or the C# reference pages.

verbatim strings

Strings may normally contain the escape sequences described above. But you may prefix a string with @ to create a verbatim string in which the backslash is an ordinary character. A verbatim string may even contain newlines:

    WriteLine(@"\one\
    \two\
    \three\"
    );

writes

\one\
\two\
\three\

format strings

A interpolated value may be followed by a format specifier (preceded by a colon).

There are many predefined format specifiers. Many format specifiers can be followed by an integer called the precision, whose meaning varies among specifiers. Here are a few of the most useful:

For example,

    const int i = 1357;
    const double pi = 3.14159;

    WriteLine($"{i:d6} {pi:f2} {i:n0}");

writes

    001357 3.14 1,357

conditional operator

The conditional operator (? :) is similar to the if statement, but it is an expression, not a statement. It takes a Boolean value and two extra values. It returns the first of these values if the boolean is true, or the second if it is false. For example, the following statement computes the greater of i and j and assigns it to k:

    int i, j;
    ...
    int k = (i > j ? i : j);

ref and out parameters

A parameter marked with ref is passed by reference: the method can modify the variable that is passed. Here's a method that swaps two variables:

    static void swap(ref int a, ref int b) {
      int t = a;
      a = b;
      b = t;
    }

You must include the keyword ref when passing an argument by reference:

    int i = 3, j = 4;
    swap(ref i, ref j);

A parameter marked with out returns a value to the caller. This method takes two integers and returns both their sum and product:

    static void sumAndProduct(int a, int b, out int sum, out int product) {
      sum = a + b;
      product = a * b;
    }

You must include the keyword out when passing a variable to an out parameter:

    int s, p;
    sumAndProduct(3, 4, out s, out p);

You can declare a new variable as you invoke a method with an out parameter. The following is equivalent to the two preceding lines:

    sumAndProduct(3, 4, out int s, out int p);

parameter arrays (params)

If the last parameter to a method is marked with params and has type T[], then in its place the method can receive any number of arguments of type T. The caller may pass individual values separated by commas, or may pass an array of type T[].

For example, this method receives a parameter array of integers and returns their sum:

    static int sum(params int[] a) {
      int s = 0;
      foreach (int i in a)
        s += i;
      return s;
    }

It can be invoked as

    int s = sum(4, 5, 6);

Alternatively, the caller can pass an array:

    int[] a = { 4, 5, 6 };
    int s = sum(a);

overloaded methods

You may declare multiple methods that have the same name but have different numbers and/or types of parameters. This is called method overloading. For example:

  static int more(int i) => i + 1

  static int more(short s) => s + 2
  
  static string more(string s) => s + " "

When calling an overloaded method, sometimes there is more than one candidate method. For example, consider this method call:

  byte b = 77;
  WriteLine(more(b));

Both of the first two method declarations above are candidates for this call, since byte is implicitly convertible to both int and short. In this situation, C# will favor the overload that involves converting to a more specific type. short is more specific than int, so in the example above C# will call the method

  int more(short s)

and will write the value 79.

For any types T and U, C# considers T to be more specific than U if there is an implicit conversion from T to U, but none from to U.

value and reference types

Every type in C# is either a value type or a reference type.

When a variable's type is a value type, the variable holds a value. An assignment between variables of value type copies the value from one variable to another.

When a variable's type is a reference type, the variable holds a pointer to an object. An assignment between variables of reference type makes them point to the same object.

For example:

    int[] a = { 4, 5, 6 };
    int[] b = a;       // now b and a point to the same array
    a[1] = 7;
    WriteLine(b[1]);   // writes 7

null

Any variable of reference type may hold the special value null.

Note especially that null is not the same as the empty string.

classes

A class is an abstract data type that can contain fields, methods, and other kinds of members.

Here is a definition for a simple class representing a point in two dimensions. It has two fields, one constructor and two methods:

using static System.Math;

class Point {
  double x, y;
  
  public Point(double x, double y) { this.x = x; this.y = y; }
  
  public void move(double dx, double dy) {
    x += dx;
    y += dy;
  }

  public double distanceFromOrigin() {
    return Sqrt(x * x + y * y);
  }
}

this

this is a special value that refers to the object on which a method, constructor or other member was invoked.

access levels

Every member in a class can be either public or private. (There are additional access levels that we will learn about soon.) public members are visible outside the class; private members can be used only within the class.

The default access level is private.

constructors

A constructor makes a new instance of a class. It always has the same name as its containing class.

To call a constructor, use the new operator and pass any required arguments:

    Point p = new Point(3.0, 4.0);

If a class definition includes no constructors, then C# provides a default constructor that takes no arguments.

Constructors may be overloaded. A constructor may call another constructor; this is called constructor chaining. For example, we could add a second constructor to the Point class that chains to the constructor with two parameters:

    public Point(double x) : this(x, 0.0) {  }

overriding ToString

For any class, you may define a ToString method that converts an instance of the class to a string. For example:

    public override string ToString() => $"({x}, {y})";

(We will learn more about override when we discuss inheritance in an upcoming lecture.)