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;

}