private static void CreateBookAndGetStatistics() { // The reference to this assembly allows me to use this class to introduce // speech into my program. It is loaded by the dynamic language runtime // when the class is requested //SpeechSynthesizer speech = new SpeechSynthesizer(); //speech.Speak("Hello, welcome to this stupid gradebook program"); GradeBook book = new GradeBook(); try { Console.Write("Enter a name: "); // Ideally, you should not set the Name property until after you know you have // a valid value. You could do this by using a combination of a variable // and a loop which keeps prompting the user until they enter a valid value // and then, once they do, you are good to store the value of that variable // into the Name property book.Name = Console.ReadLine(); } // Catch blocks can be chained and the first one to match will be the one that // executes and all the others will be skipped. Thus, include the most specific // exception blocks first. catch (ArgumentException ex) { Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); } // The Exception type is the most general, from which most others inherit, so it // comes last. There are only a few which it cannot catch. These are the ones // that are guaranteed to crash your program. Catching one this general could // be dangerous since you don't know what kind of exception it is. catch (Exception ex) { Console.WriteLine(ex.Message); } // Finally is good to add at the end to clean up any resources, regardless // of wheather or not there is an exception thrown. book.NameChanged = new NameChangedDelegate(OnNameChanged); //book.NameChanged = OnNameChanged; // sugar! // This is legal for delegates. But, if it were an event, you couldn't do this. // Usually, you should prefer events to provide encapsulation. Events bascially // translate into a private delegate behind the scenes which only publiclly expose // subscribe (+=) and unsubscripe (-=) methods. //book.NameChanged = OnNameChanged2; This will overwrite the delegate, effectively removing all subscribers. //book.NameChanged("Hehehehe", "I'm invoking the delegate directly from outside the class"); book.NameChanged += OnNameChanged2; // This creates a multicast delegate. book.NameChanged -= OnNameChanged2; // Removes it from the multicast delegate // Events: book.NameChangedEvent += OnNameChanged; // You can only subscribe and unsubscribe from events. you cannot // invoke or assign to them directly but only from within the methods // of the class. //book.NameChangedEvent("This is no longer legal", "Compile Error!!!!"); //book.NameChangedEvent = null; // Compile error!! // Events using convention with the title. book.TitleChanged += OnTitleChanged; book.Title = "Title"; // This will invoke the set method on the Name property, passing in // "Jeff's Grade Book" as the "value". book.Name = "Jeff's Grade Book"; book.AddGrade(81); // 81 is converted to a float book.AddGrade(75); book.AddGrade(91.5f); // book.AddGrade(53.4); // Compile error, cannot convert double to float. GradeStatistics stats = book.ComputeStatistics(); WriteResult("Average", stats.AverageGrade); // calls the one with a float result WriteResult("Highest", (int)stats.HighestGrade); // calls the one with a int result (it truncates) WriteResult("Lowest", stats.LowestGrade); // You can't do this because you are in a static method. Non-static fields // and methods are implicitly passed 'this', which is a reference to the // object calling the method, which you don't have in a static method and // therefore cannot pass to the non-static method or field. In short, if you // are in a static method, you can only access other static methods/properties. //MyProperty = 3; }