Solutions for those exercises.

Questions

  1. What is the difference between ref and out?

    • ref variables are “read-only”, their value cannot change inside a method.
    • ref is a keyword, out is not.
    • There isn’t any: they are both used to pass a reference to a method.
    • out variables may not be initialized going into the method, but have to receive a value inside the method.
    • There isn’t any: they are both used to pass a value to a method.
  2. What would be displayed by the following?

        static void AddR(ref int a, ref int b){
          int tmp = a;
          a = a + b;
          b = tmp - b;
        }
        
        int x = 4, y = 3;
        Console.WriteLine($"x is {x}, y is {y}.");
        AddR(ref x, ref y);
        Console.WriteLine($"x is {x}, y is {y}.");

    (Download this code)

    • “x is {x}, y is {y}.”, “x is {x}, y is {y}.”
    • “x is 4, y is 3.”, “x is 3, y is 4.”
    • “x is 4, y is 3.”, “x is 4, y is 3.”
    • “x is 4, y is 3.”, “x is 7, y is 1.”
    • This code would not compile.
  3. The following method would not compile. Why?

        static void Test1(int a, out int b){
          if (a > 0) { b = 12; }
        }

    (Download this code)

    • A method cannot be static and have void as a return type.
    • Any out parameter must have its value set in the body of the method.
    • The else is missing.
    • C# assumes that out parameters do not have a value.
    • The keyword out cannot be used in the header of a method.
    • An out parameter cannot be assigned a value.
  4. The following method would not compile. Why?

         static void Test2(int a, out int b){
                     if (b < 0) { b = a; }
                     else { b = 10;}
         }

    (Download this code)

    • A method cannot be static and have void as a return type.
    • Any out parameter must have its value set in the body of the method.
    • C# assumes that out parameters do not have a value.
    • The keyword out cannot be used in the header of a method.
    • An out parameter cannot be assigned a value.

Warm-up Exercises

  1. Consider the following code:

    using System;
     
    class Program
    {
      static void Main()
      {
        int x = 1;
        int y = 2;
        int z;
        char c = Foo(x, ref y, out z);
        char d = Foo(x, ref y, out z, '%');
      }
     
      static char Foo(
        int x,
        ref int y,
        out int z,
        char symb = '*'
      )
      {
        x++;
        y--;
        z = x + y;
        return symb;
      }
    }

    (Download this code)

    1. What are the values of x, y and z

      1. Before the Foo method is called?
      2. Inside the Foo method?
      3. After the Foo method executed?
    2. What is the value of c?

    3. What is the value of d?

  2. Consider the following method:

        static void NameChange(
          ref string nameP,
          string newnameP,
          out string oldnameP
        )
        {
          oldnameP = nameP;
          nameP = newnameP;
        }

    (Download this code) Assume given a string name variable containing a value. Write a short program (possibly declaring additional variables) that

    1. Asks the user their new name,
    2. Calls the NameChange method with appropriate arguments,
    3. Displays the new name and the old name.

Problems

  1. Write the AddLog method (header included) such that the following:

        string log;
        int x1 = 4,
        y1 = 3;
        int result = AddLog(x1, y1, out log);
        Console.WriteLine(log + "\n" + result);
        

    (Download this code) would display

    4 + 3 = 7.
    7
  2. Write the AddReset method (header included) such that the following:

        int x2 = 2,
        y2 = 3,
        z2;
        AddReset(ref x2, ref y2, out z2);
        Console.WriteLine($"x2 = {x2}, y2 = {y2}, z2 = {z2}.");

    (Download this code) would display

    x2 = 0, y2 = 0, z2 = 5.
  3. Consider the “regular” implementation of the Rectangle class:

    using System;
    class Rectangle
    {
        private int length;
        public int Length
        {
            get { return length; }
            set {
                if (value < 0) {
                    throw new ArgumentNullException();
                } 
                else length = value; 
                }
        }
     
        private int width;
        public int Width
        {
            get { return width; }
            set { if (value < 0) { throw new ArgumentNullException(); } else width = value; }
        }
     
        public Rectangle(int wP, int lP)
        {
            Width = wP;
            Length = lP;
        }
     
        public override string ToString()
        {
            return $"Width: {Width}\nLength: {Length}";
        }
    }

    And try to answer the following questions.

    1. Write a Draw method that takes one optional char parameter and draw a rectangle of the calling object’s width and length using that character if provided, * otherwise. If your method is correctly implemented, then

      Rectangle r0 = new Rectangle(3, 2);
       
      r0.Draw();
      r0.Draw('-');

      should display

      ***
      ***
       
      ---
      ---
    2. Write a Copy method that does not take arguments, and return a copy of the calling object. If your method is correctly implemented, then

      Rectangle original = new Rectangle(5, 10);
      Rectangle copy = original.Copy();
      Console.WriteLine("Original:\n" + original + "\nCopy:\n"+ copy + "\n");
      copy.Length = 12;
      Console.WriteLine("\nOriginal:\n" + original + "\nCopy:\n" + copy + "\n");

      should display

      Original:
      Width: 5
      Length: 10
      Copy:
      Width: 5
      Length: 10
       
       
      Original:
      Width: 5
      Length: 10
      Copy:
      Width: 5
      Length: 12

      If the length of the original object changed after copy.Length = 12; was executed, then your method makes a shallow copy instead of a “deep” copy.

    3. Write an Equals method that return true if the calling object and the argument are both non-null rectangles with the same length and width, false otherwise. If your method is correctly implemented, then

      Rectangle r1 = new Rectangle(5, 10);
      Rectangle r2 = new Rectangle(5, 10);
      Rectangle r3 = null;
      Rectangle r4 = r1;
      Rectangle r5 = new Rectangle(10, 5);
       
      Console.WriteLine(
          "r1 and r2 identical: " + r1?.Equals(r2)
          + "\nr1 and r3 identical: " + r1?.Equals(r3)
          + "\nr3 and r1 identical: " + r3?.Equals(r1)
          + "\nr3 and r3 identical: " + r3?.Equals(r3)
          + "\nr1 and r4 identical: " + r1?.Equals(r4)
          + "\nr1 and r5 identical: " + r1?.Equals(r5)
          );

      should display

      r1 and r2 identical: True
      r1 and r3 identical: False
      r3 and r1 identical: 
      r3 and r3 identical: 
      r1 and r4 identical: True
      r1 and r5 identical: False