C#
Rosetta.cs
// 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;
this.AfterTouch(after);
// NOTE that [fmt35] doesn't apply in C#
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;
}