From: gu.martinm@gmail.com Date: Fri, 20 Dec 2013 21:42:17 +0000 (+0100) Subject: C# In Depth: Chapters 5 and 6 X-Git-Url: https://git.gumartinm.name/?a=commitdiff_plain;h=f9b61a3de4f1e500022bacaa35d5fec6b59eaa7e;p=CSharpForFun%2F.git C# In Depth: Chapters 5 and 6 --- diff --git a/CSharpInDepth/Chapter5/Chapter5.sln b/CSharpInDepth/Chapter5/Chapter5.sln new file mode 100644 index 0000000..b6a79a4 --- /dev/null +++ b/CSharpInDepth/Chapter5/Chapter5.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Chapter5", "Chapter5\Chapter5.csproj", "{06326E93-0CD5-488A-A283-D26D36968815}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {06326E93-0CD5-488A-A283-D26D36968815}.Debug|x86.ActiveCfg = Debug|x86 + {06326E93-0CD5-488A-A283-D26D36968815}.Debug|x86.Build.0 = Debug|x86 + {06326E93-0CD5-488A-A283-D26D36968815}.Release|x86.ActiveCfg = Release|x86 + {06326E93-0CD5-488A-A283-D26D36968815}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = Chapter5\Chapter5.csproj + EndGlobalSection +EndGlobal diff --git a/CSharpInDepth/Chapter5/Chapter5.userprefs b/CSharpInDepth/Chapter5/Chapter5.userprefs new file mode 100644 index 0000000..d763d61 --- /dev/null +++ b/CSharpInDepth/Chapter5/Chapter5.userprefs @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/CSharpInDepth/Chapter5/Chapter5/AssemblyInfo.cs b/CSharpInDepth/Chapter5/Chapter5/AssemblyInfo.cs new file mode 100644 index 0000000..c378ed2 --- /dev/null +++ b/CSharpInDepth/Chapter5/Chapter5/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("Chapter5")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("gustavo")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/CSharpInDepth/Chapter5/Chapter5/Chapter5.csproj b/CSharpInDepth/Chapter5/Chapter5/Chapter5.csproj new file mode 100644 index 0000000..d92dd08 --- /dev/null +++ b/CSharpInDepth/Chapter5/Chapter5/Chapter5.csproj @@ -0,0 +1,74 @@ + + + + Debug + x86 + 10.0.0 + 2.0 + {06326E93-0CD5-488A-A283-D26D36968815} + WinExe + Chapter5 + Chapter5 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + x86 + false + + + none + true + bin\Release + prompt + 4 + x86 + false + + + + + False + gtk-sharp-2.0 + + + False + gtk-sharp-2.0 + + + False + glib-sharp-2.0 + + + False + glade-sharp-2.0 + + + False + gtk-sharp-2.0 + + + False + gtk-sharp-2.0 + + + + + + gui.stetic + + + + + + + + + + + \ No newline at end of file diff --git a/CSharpInDepth/Chapter5/Chapter5/Main.cs b/CSharpInDepth/Chapter5/Chapter5/Main.cs new file mode 100644 index 0000000..5cf439d --- /dev/null +++ b/CSharpInDepth/Chapter5/Chapter5/Main.cs @@ -0,0 +1,306 @@ +using System; +using Gtk; +using System.IO; +using System.Collections.Generic; + +namespace Chapter5 +{ + class MainClass + { + delegate Stream StreamFactory(); + delegate void SampleDelegate(string x); + delegate void MethodInvoker(); + + public static void Main (string[] args) + { + Application.Init (); + + MainWindow win = new MainWindow (); + + + /** + * + * Listing 5.1 Subscribing to three of a button's events. + */ + Button buttonA = new Button ("Click me 5.1"); + buttonA.Pressed += new EventHandler (LogPlainEvent); + buttonA.KeyPressEvent += new KeyPressEventHandler (LogKeyEvent); + win.Add (buttonA); + + + /** + * + * Listing 5.2 Demonstration of method group conversion and delegate contravariance. + */ + Button buttonB = new Button ("Click me 5.2"); + buttonB.Pressed += LogPlainEvent; + buttonB.KeyPressEvent += LogPlainEvent; + win.Add (buttonB); + + + /** + * + * Listing 5.3 Demonstration of covariance of return types for delegates. + */ + StreamFactory factoryA = GenerateSampleData; + + using (Stream stream = factoryA()) { + int data; + + while ((data = stream.ReadByte()) != -1) { + Console.WriteLine (data); + } + } + + + /** + * + * Listing 5.4 Demonstration of braking change between C# 1 and C# 2. + */ + Derived x = new Derived (); + SampleDelegate factoryB = new SampleDelegate (x.CandidateAction); + factoryB ("test"); + + + /** + * + * Listing 5.5 Anonymous methods used with the Action delegate type. + */ + Action printReverse = delegate(string text) { + char[] chars = text.ToCharArray (); + Array.Reverse (chars); + Console.WriteLine (new String (chars)); + }; + + Action printRoot = delegate(int number) { + Console.WriteLine (Math.Sqrt (number)); + }; + + Action> printMean = delegate(IList numbers) { + double total = 0; + foreach (double value in numbers) { + total += value; + } + Console.WriteLine (total / numbers.Count); + }; + + printReverse ("Hello Gus"); + printRoot (2); + printMean (new double[] {1.5, 2.5, 3.5, 4.5, 5, 7, 10.1}); + + + /** + * + * Listing 5.7 Returning a value from an anonymous method. + */ + Predicate isEven = delegate(int number) { + return number % 2 == 0; + }; + Console.WriteLine (isEven (1)); + Console.WriteLine (isEven (4)); + + + /** + * + * Listing 5.8 Using anonymous methods to sort files simply. + */ + SortAndShowFiles ("Sorted by name:", delegate(FileInfo f1, FileInfo f2) { + return f1.Name.CompareTo (f2.Name); + } + ); + + SortAndShowFiles ("Sorted by length:", delegate(FileInfo f1, FileInfo f2) { + return f1.Length.CompareTo (f2.Length); + } + ); + + + /** + * + * Listing 5.9 Subscribing to event with anonymous methods that ignore parameters. + */ + Button buttonC = new Button ("Click me 5.9"); + buttonC.Pressed += delegate { + Console.WriteLine ("LogPlain"); + }; + buttonC.KeyPressEvent += delegate { + Console.WriteLine ("LogKey"); + }; + win.Add (buttonC); + + + /** + * + * Listing 5.10 Examples of variable kinds with respect to anonymous methods. + */ + int outerVariable = 5; + string capturedVariable = "captured"; + + if (DateTime.Now.Hour == 1) { + int normalLocalVariable = DateTime.Now.Minute; + Console.WriteLine (normalLocalVariable); + } + + MethodInvoker method = delegate() { + string anonLocal = " local to anonymous method"; + Console.WriteLine (capturedVariable + anonLocal); + }; + method (); + + + /** + * + * Listing 5.11 Accessing a variable both inside and outside an anonymous method. + */ + string captured = "before methodB is created"; + + MethodInvoker methodB = delegate { + Console.WriteLine (captured); + captured = "changed by methodB"; + }; + captured = "directly before methodB is invoked"; + methodB (); + + Console.WriteLine (captured); + + captured = "before second invocation"; + methodB (); + + + /** + * + * Listing 5.12 Demonstration of a captured variable having its lifetime extended. + */ + MethodInvoker methodC = CreateDelegateInstance (); + methodC (); + methodC (); + + + /** + * + * Listing 5.13 Capturing multiple variable instantiations with multiple delegates. + */ + List list = new List (); + + // The variable declared by the initial part of the loop is only instantiated once. + for (int index = 0; index < 5; index++) { + // Because counter is declared inside the loop, it's instantiated for each iteration. + int counter = index * 10; + list.Add (delegate { + Console.WriteLine (counter); + counter++; + } + ); + } + + foreach (MethodInvoker t in list) { + t (); + } + list [0] (); + list [0] (); + list [0] (); + + list [1] (); + + + /** + * + * Listing 5.14 Capturing variables in different scopes. Warning: nasty code ahead! + */ + MethodInvoker[] delegates = new MethodInvoker[2]; + + int outside = 0; + + for (int i = 0; i < 2; i++) { + // Because inside is declared inside the loop, it's instantiated for each iteration. + int inside = 0; + + delegates[i] = delegate { + Console.WriteLine ("({0},{1})", outside, inside); + outside++; + inside++; + }; + } + + MethodInvoker first = delegates[0]; + MethodInvoker second = delegates[1]; + + first(); + first(); + first(); + + second(); + second(); + + + + win.ShowAll (); + Application.Run (); + } + + + static void LogPlainEvent (object sender, EventArgs e) + { + Console.WriteLine("LogPlain"); + } + + + static void LogKeyEvent (object sender, KeyPressEventArgs e) + { + Console.WriteLine("LogKey"); + } + + + static MemoryStream GenerateSampleData () + { + byte[] buffer = new byte[16]; + for (int i = 0; i < buffer.Length; i++) { + buffer[i] = (byte) i; + } + + return new MemoryStream(buffer); + } + + + public void CandidateAction(string x) + { + Console.WriteLine("Snippet.CandidateAction"); + } + + + public class Derived:MainClass + { + public void CandidateAction(object o) + { + Console.WriteLine("Derived.CandidateAction"); + } + } + + static void SortAndShowFiles (string title, Comparison sortOrder) + { + FileInfo[] files = new DirectoryInfo (@"/").GetFiles (); + + Array.Sort (files, sortOrder); + + Console.WriteLine (title); + foreach (FileInfo file in files) { + Console.WriteLine(" {0} ({1} bytes)", file.Name, file.Length); + } + } + + static MethodInvoker CreateDelegateInstance () + { + int counter = 5; + + MethodInvoker ret = delegate + { + Console.WriteLine(counter); + counter++; + }; + + ret(); + return ret; + } + } + +} diff --git a/CSharpInDepth/Chapter5/Chapter5/MainWindow.cs b/CSharpInDepth/Chapter5/Chapter5/MainWindow.cs new file mode 100644 index 0000000..b450b52 --- /dev/null +++ b/CSharpInDepth/Chapter5/Chapter5/MainWindow.cs @@ -0,0 +1,16 @@ +using System; +using Gtk; + +public partial class MainWindow: Gtk.Window +{ + public MainWindow (): base (Gtk.WindowType.Toplevel) + { + Build (); + } + + protected void OnDeleteEvent (object sender, DeleteEventArgs a) + { + Application.Quit (); + a.RetVal = true; + } +} diff --git a/CSharpInDepth/Chapter5/Chapter5/bin/Debug/Chapter5.exe b/CSharpInDepth/Chapter5/Chapter5/bin/Debug/Chapter5.exe new file mode 100755 index 0000000..c5745e9 Binary files /dev/null and b/CSharpInDepth/Chapter5/Chapter5/bin/Debug/Chapter5.exe differ diff --git a/CSharpInDepth/Chapter5/Chapter5/bin/Debug/Chapter5.exe.mdb b/CSharpInDepth/Chapter5/Chapter5/bin/Debug/Chapter5.exe.mdb new file mode 100644 index 0000000..22a0c61 Binary files /dev/null and b/CSharpInDepth/Chapter5/Chapter5/bin/Debug/Chapter5.exe.mdb differ diff --git a/CSharpInDepth/Chapter5/Chapter5/gtk-gui/MainWindow.cs b/CSharpInDepth/Chapter5/Chapter5/gtk-gui/MainWindow.cs new file mode 100644 index 0000000..7d75d57 --- /dev/null +++ b/CSharpInDepth/Chapter5/Chapter5/gtk-gui/MainWindow.cs @@ -0,0 +1,27 @@ + +// This file has been generated by the GUI designer. Do not modify. + +public partial class MainWindow +{ + private global::Gtk.UIManager UIManager; + + protected virtual void Build () + { + global::Stetic.Gui.Initialize (this); + // Widget MainWindow + this.UIManager = new global::Gtk.UIManager (); + global::Gtk.ActionGroup w1 = new global::Gtk.ActionGroup ("Default"); + this.UIManager.InsertActionGroup (w1, 0); + this.AddAccelGroup (this.UIManager.AccelGroup); + this.Name = "MainWindow"; + this.Title = global::Mono.Unix.Catalog.GetString ("MainWindow"); + this.WindowPosition = ((global::Gtk.WindowPosition)(4)); + if ((this.Child != null)) { + this.Child.ShowAll (); + } + this.DefaultWidth = 400; + this.DefaultHeight = 300; + this.Show (); + this.DeleteEvent += new global::Gtk.DeleteEventHandler (this.OnDeleteEvent); + } +} diff --git a/CSharpInDepth/Chapter5/Chapter5/gtk-gui/generated.cs b/CSharpInDepth/Chapter5/Chapter5/gtk-gui/generated.cs new file mode 100644 index 0000000..9636f6f --- /dev/null +++ b/CSharpInDepth/Chapter5/Chapter5/gtk-gui/generated.cs @@ -0,0 +1,29 @@ + +// This file has been generated by the GUI designer. Do not modify. +namespace Stetic +{ + internal class Gui + { + private static bool initialized; + + internal static void Initialize (Gtk.Widget iconRenderer) + { + if ((Stetic.Gui.initialized == false)) { + Stetic.Gui.initialized = true; + } + } + } + + internal class ActionGroups + { + public static Gtk.ActionGroup GetActionGroup (System.Type type) + { + return Stetic.ActionGroups.GetActionGroup (type.FullName); + } + + public static Gtk.ActionGroup GetActionGroup (string name) + { + return null; + } + } +} diff --git a/CSharpInDepth/Chapter5/Chapter5/gtk-gui/gui.stetic b/CSharpInDepth/Chapter5/Chapter5/gtk-gui/gui.stetic new file mode 100644 index 0000000..58b3a44 --- /dev/null +++ b/CSharpInDepth/Chapter5/Chapter5/gtk-gui/gui.stetic @@ -0,0 +1,21 @@ + + + + .. + 2.12 + + + + + + + + + MainWindow + CenterOnParent + + + + + + \ No newline at end of file diff --git a/CSharpInDepth/Chapter6/Chapter6.sln b/CSharpInDepth/Chapter6/Chapter6.sln new file mode 100644 index 0000000..0def22a --- /dev/null +++ b/CSharpInDepth/Chapter6/Chapter6.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Chapter6", "Chapter6\Chapter6.csproj", "{DD91EB8A-A3C0-4A8D-A529-82621728B868}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DD91EB8A-A3C0-4A8D-A529-82621728B868}.Debug|x86.ActiveCfg = Debug|x86 + {DD91EB8A-A3C0-4A8D-A529-82621728B868}.Debug|x86.Build.0 = Debug|x86 + {DD91EB8A-A3C0-4A8D-A529-82621728B868}.Release|x86.ActiveCfg = Release|x86 + {DD91EB8A-A3C0-4A8D-A529-82621728B868}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(MonoDevelopProperties) = preSolution + StartupItem = Chapter6\Chapter6.csproj + EndGlobalSection +EndGlobal diff --git a/CSharpInDepth/Chapter6/Chapter6.userprefs b/CSharpInDepth/Chapter6/Chapter6.userprefs new file mode 100644 index 0000000..2147a1e --- /dev/null +++ b/CSharpInDepth/Chapter6/Chapter6.userprefs @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/CSharpInDepth/Chapter6/Chapter6/AssemblyInfo.cs b/CSharpInDepth/Chapter6/Chapter6/AssemblyInfo.cs new file mode 100644 index 0000000..2d11b04 --- /dev/null +++ b/CSharpInDepth/Chapter6/Chapter6/AssemblyInfo.cs @@ -0,0 +1,27 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// Information about this assembly is defined by the following attributes. +// Change them to the values specific to your project. + +[assembly: AssemblyTitle("Chapter6")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("gustavo")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}". +// The form "{Major}.{Minor}.*" will automatically update the build and revision, +// and "{Major}.{Minor}.{Build}.*" will update just the revision. + +[assembly: AssemblyVersion("1.0.*")] + +// The following attributes are used to specify the signing key for the assembly, +// if desired. See the Mono documentation for more information about signing. + +//[assembly: AssemblyDelaySign(false)] +//[assembly: AssemblyKeyFile("")] + diff --git a/CSharpInDepth/Chapter6/Chapter6/Chapter6.csproj b/CSharpInDepth/Chapter6/Chapter6/Chapter6.csproj new file mode 100644 index 0000000..4e1f340 --- /dev/null +++ b/CSharpInDepth/Chapter6/Chapter6/Chapter6.csproj @@ -0,0 +1,41 @@ + + + + Debug + x86 + 10.0.0 + 2.0 + {DD91EB8A-A3C0-4A8D-A529-82621728B868} + Exe + Chapter6 + Chapter6 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + x86 + true + + + none + true + bin\Release + prompt + 4 + x86 + true + + + + + + + + + + \ No newline at end of file diff --git a/CSharpInDepth/Chapter6/Chapter6/Main.cs b/CSharpInDepth/Chapter6/Chapter6/Main.cs new file mode 100644 index 0000000..bbd61f5 --- /dev/null +++ b/CSharpInDepth/Chapter6/Chapter6/Main.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Chapter6 +{ + class MainClass + { + static readonly string Padding = new string(' ', 30); + + public static void Main (string[] args) + { + + /** + * + * Listings 6.1 and 6.2 Skeleton of th new collection type, with no iterator implementation. + */ + object[] values = {"a", "b", "c", "d", "e"}; + IterationSampleBad badCollection = new IterationSampleBad(values, 3); + try { + foreach(object x in badCollection) + { + Console.WriteLine(x); + } + } catch(NotImplementedException e) { + Console.WriteLine("Listings 6.1 and 6.2 exception: {0}", e); + } + + + /** + * + * Listings 6.3 Nested class implementing the collection's iterator. + */ + IterationSample collection = new IterationSample(values, 3); + foreach(object x in collection) + { + Console.WriteLine(x); + } + + + /** + * + * Listings 6.4 Iterating through the sample collection with C# 2 and yield return. + */ + IterationSampleYield yieldCollection = new IterationSampleYield(values, 3); + foreach(object x in yieldCollection) + { + Console.WriteLine(x); + } + + + /** + * + * Listings 6.5 Showing the sequence of calls between an iterator and its caller. + */ + IEnumerable iterable = CreateEnumerable(); + IEnumerator iterator = iterable.GetEnumerator(); + Console.WriteLine("Starting to iterate"); + } + + static IEnumerable CreateEnumerable () + { + Console.WriteLine ("{0}Start of CreateEnumerable()", Padding); + + for (int i=0; i < 3; i++) { + Console.WriteLine("{0}About to yield {1}", Padding, i); + yield return i; + Console.WriteLine("{0}After yield", Padding); + } + + Console.WriteLine("{0}Yielding final value", Padding); + yield return -1; + + Console.WriteLine("{0}End of CreateEnumerable()", Padding); + } + } + + + public class IterationSampleBad : IEnumerable + { + object[] values; + int startingPoint; + + public IterationSampleBad (object[] values, int startingPoint) + { + this.values = values; + this.startingPoint = startingPoint; + } + + public IEnumerator GetEnumerator() + { + throw new NotImplementedException(); + } + } + + + // The same as the Java style of creating a custom Iterator: + // see http://stackoverflow.com/questions/5849154/can-we-write-our-own-iterator-in-java + // (basically it is the same) + public class IterationSample : IEnumerable + { + object[] values; + int startingPoint; + + public IterationSample (object[] values, int startingPoint) + { + this.values = values; + this.startingPoint = startingPoint; + } + + public IEnumerator GetEnumerator() + { + // If GetEnumerator is called several times, serveral independent iterators should be returned. + return new IterationSampleIterator(this); + } + + // Let's create another nested class to implement the iterator itself. + public class IterationSampleIterator : IEnumerator + { + IterationSample parent; + // Iterators are stateful. We need to store some state somewhere (the position in this example) + int position; + + internal IterationSampleIterator (IterationSample parent) + { + this.parent = parent; + position = -1; + } + + public bool MoveNext () + { + if (position != parent.values.Length) { + position++; + } + return position < parent.values.Length; + } + + public object Current { + get { + if (position == -1 || + position == parent.values.Length) { + throw new InvalidOperationException(); + } + int index = position + parent.startingPoint; + index = index % parent.values.Length; + return parent.values[index]; + } + } + + public void Reset() + { + position = -1; + } + } + } + + + // The C# 2.0 style! Rocks! + public class IterationSampleYield : IEnumerable + { + object[] values; + int startingPoint; + + public IterationSampleYield (object[] values, int startingPoint) + { + this.values = values; + this.startingPoint = startingPoint; + } + + public IEnumerator GetEnumerator () + { + // * Whenever MoveNext is called, it has to execute code from the GetEnumerator + // method until you are ready to provide the next value (in other words, until you + // hit a yield return statement) + // * When the Current property is used, it has to return the last value you yielded. + // * It has to know when you have finished yielding values so that MoveNext can return false. + for (int index = 0; index < values.Length; index++) { + yield return values[(index + startingPoint) % values.Length]; + } + } + } +} diff --git a/CSharpInDepth/Chapter6/Chapter6/bin/Debug/Chapter6.exe b/CSharpInDepth/Chapter6/Chapter6/bin/Debug/Chapter6.exe new file mode 100755 index 0000000..e2cf7af Binary files /dev/null and b/CSharpInDepth/Chapter6/Chapter6/bin/Debug/Chapter6.exe differ diff --git a/CSharpInDepth/Chapter6/Chapter6/bin/Debug/Chapter6.exe.mdb b/CSharpInDepth/Chapter6/Chapter6/bin/Debug/Chapter6.exe.mdb new file mode 100644 index 0000000..03887f8 Binary files /dev/null and b/CSharpInDepth/Chapter6/Chapter6/bin/Debug/Chapter6.exe.mdb differ