Rosettas‎ > ‎

C#


// Copyright (c) 2008 Art & Logic, Inc. All Rights Reserved.
// $Id: Rosetta.cs,v 1.7 2008/03/20 18:26:06 bporter Exp $

// Above: [sf02], [sf03] 

// a note on the stuff inside the square brackets:
// Each of the codes inside brackets is a reference to the rule(s) in the
// Style Guide that's being illustrated, as follows:
// [sf##] - StyleGuide/SourceFiles
// [cas##] - StyleGuide/ClassesAndStructures
// [nr##] - StyleGuide/NamingRules
// [cg##] - StyleGuide/Commenting
// [fmt##] - StyleGuide/Formatting

// Throughout: [fmt01]; all indentation done with space characters (0x20),
// three spaces per logical tab stop.

using System;
using System.IO;
using System.Diagnostics;

/// <summary>
/// Simple, but meaningless class to demonstrate Art & Logic programming
/// style conventions as they are applied to the various programming languages
/// we use. In several places, you're asked to imagine a block of useful code
/// to avoid distracting you from the issues of formatting (etc) that are
/// being demonstrated.
/// 
/// As you've already seen above, the thing about to be shown in this file is
/// called out in comments using the A&L-style markup '!!!'
/// </summary>
public class ARosetta : IDisposable
{
   /// <summary>
   /// Constructor.
   /// </summary>
   /// <param name="fileName">Full path to file containing Rosetta.</param>
   public ARosetta(string fileName)
   {
      fFileName = fileName;
      fInputFile = File.Open(fileName, FileMode.Open, FileAccess.Read);
   }

   /// <summary>
   /// Demonstrates various code constructs.
   /// </summary>
   /// <returns>True for success, false otherwise.</returns>
   public virtual bool MemberFunctionWithMultipleWords()
   {
      bool ok = true;

      // [fmt08] -- formatting  of a for() loop.
      for (int i = 0; i < kSomeConstant; ++i)
      {
         for (int j = 0; j < kSomeOtherConstant; ++j)
         {
            Debug.Print("Testing: {0}, {1}", i, j);

            // [nr07] -- Calls to member functions of the current object are
            //  made through an explicit "this" keyword.
            ok = this.Test(i, j);

            if (!ok)
            {
               Console.Error.WriteLine("Fatal error testing: {0}, {1}", i, j);
               goto CleanUp;
            }
         }
      }

      return true;

// [fmt02] -- labels used as the target of a goto are placed in column zero.
CleanUp:
      // cleanup code here...
      return false;
   }

   /// <summary>
   /// Demonstrates code line wrapping.
   /// </summary>
   /// <returns>True for success, false otherwise.</returns>
   public bool LongLineWrapping()
   {
      bool retVal;

      // [fmt03] -- source lines should be less than 80 characters long.
      // [fmt04] -- break lines at the most logical point
//       1         2         3         4         5         6         7
//34567890123456789012345678901234567890123456789012345678901234567890123456789
      retVal = FunctionWithManyArguments(longArgumentName1, longArgumentName2,
       longArgumentName3, longArgumentName4);

      // alternative format #1
      retVal = FunctionWithManyArguments(longArgumentName1,
       longArgumentName2,
       longArgumentName3,
       longArgumentName4);

      // alternative format #2
      retVal = FunctionWithManyArguments(
       longArgumentName1,
       longArgumentName2,
       longArgumentName3,
       longArgumentName4);

      // [fmt05] -- prefer to break after a comma
      retVal = anObject.SomeUsefulFunction(x.LeftMargin() + x.RightMargin(),
       x.TopMargin() + x.BottomMargin() - 1);

      // [fmt05] -- if that's not possible, break after an operator
      retVal = anObject.SomeUsefulFunction(x.LeftMargin() + x.RightMargin() +
       anObject.HorizontalPadding(), x.TopMargin() + x.BottomMargin() - 1);

      return retVal;
   }

   /// <summary>
   /// Demonstrates looping constructs.
   /// </summary>
   public void Loops()
   {
      // [fmt08] -- for() loop; note the pre-incremented form of the loop
      //  control.
      for (int i = 0; i < kSomeConstant; ++i)
      {
         // loop code here...
      }

      // [fmt09]
      while (someBoolean)
      {
         // useful code...
      }

      // [fmt09] -- while loop with an empty body makes the emptiness explicit
      while (this.SomeFuncReturningBool())
      {
         // intentionally empty...
      }

      // [fmt10] -- do/while loop.
      // [fmt18] -- exception to the bracing rule saying that braces should
      //  always be on a line by themselves
      do
      {
         // loop code here...
      } while (someBoolean);
   }

   protected virtual bool Test(int firstVal, int secondVal)
   {
      bool retval = true;

      // [fmt07] -- if/else formatting
      if (firstVal < secondVal)
      {
         // [cg06] -- use '$$$' as a marker to indicate a request that the
         // following block of code be reviewed before a change is considered
         // complete
         // $$$ before
         // this.Process(secondVal);
         // $$$ after
         // Shouldn't this be processing the first value in this case?
         this.Process(firstVal);
         // $$$ end
      }
      else if (secondVal > kSomeConstant)
      {
         this.Process(secondVal);
      }
      else
      {
         // [fmt18] -- use curly braces even in cases where the language
         //  doesn't require it to prevent maintenance errors.
         retval = false;
      }

      return retval;
   }

   private void Process(int val)
   {
      // [cg05] -- use '!!!' as a marker to indicate a section of code that
      // requires attention
      // !!!... removing old hardcoded value
      // fProcessResult = 131;
      // ...!!!
      int result = val;

      while (--val > 0)
      {
         result *= val;
      }

      fProcessResult = result;
   }

   private void Decide(MidiEventType midiEventType)
   {
      // [fmt11] -- switch/case formatting.
      switch (midiEventType)
      {
         // comments precede the case
         case MidiEventType.NoteOn:
         this.NoteOn(now);
         if (duration > 0)
         {
            this.NoteOff(now + duration);
         }
         break;
         
         case MidiEventType.NoteOff:
         this.NoteOff(now);
         break;
         
         case MidiEventType.PolyAfter:
         after = channelValue;
         // [fmt35] include, but comment out the break when falling through
         //  intentionally.
         // break;

         case MidiEventType.ChannelAfter:
         this.AfterTouch(after);
         break;

         // [fmt36] no need to include a commented out break when falling
         //  through an empty case.
         case MidiEventType.PitchBend:
         // blank line...

         // [fmt12] -- switch statements should always have a default case.
         default:

         Debug.Fail("Unsupported event type!");
         this.LogError("Unsupported event type!");
         break;
      }
   }

   // Implementation of dispose/finalize pattern.
   // (msdn.com/library/en-us/cpgenref/html/cpconfinalizedispose.asp)

   public void Dispose()
   {
      this.Dispose(true);
      GC.SuppressFinalize(this);
   }

   protected virtual void Dispose(bool isDisposing)
   {
      if (fAlreadyDisposed)
      {
         return;
      }

      if (isDisposing)
      {
         fInputFile.Dispose();
      }

      fAlreadyDisposed = true;
   }

   ~ARosetta()
   {
      this.Dispose(false);
   }

   /// <summary>
   /// Represents various MIDI event types.
   /// </summary>
   // [nr10] Avoid using two (or more) consecutive uppercase letters in an
   //  identifier.
   public enum MidiEventType
   {
      kNoteOn = 0x01,
      kNoteOff = 0x02,
      kPolyAfter = 0x03,
      kChannelAfter = 0x04,
      kPitchBend = 0x05
   };

   // [nr04], [nr19] Member variables are prefixed with a lowercase 'f', followed
   //  by an uppercase letter.
   private string fFileName;
   private System.IO.FileStream fInputFile;
   private int fProcessResult = 0;
   private bool fAlreadyDisposed = false;

   // [nr23] identifiers specifying constants for the program are always
   //  prefixed with a lowercase 'k'.
   private const int kSomeConstant = 64;
   private const int kSomeOtherConstant = 90;
}