• Stars
    star
    168
  • Rank 225,507 (Top 5 %)
  • Language
    C#
  • License
    MIT License
  • Created about 10 years ago
  • Updated over 4 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

C# : Test-Driven Learning

C# : Test-Driven Learning

This project is aimed to help the user further study C# with a test-driven approach. Each unit contains an annotated tutorial and a platform where you can test your understanding of the topic.

Topics:

  • Fundamentals
  • Classes and Objects
  • Primitive Types
  • Types
  • Events
  • Access Modifiers
  • Arrays
  • Boxing
  • Exceptions
  • Loops
  • Methods
  • Operators
  • Value Types
  • Garbage Collection
  • Threads
  • Reflection
  • COM Interop
  • PInvoke
  • Generics

Tools

Basics

using System;  //Use 'using' keyword to tell the compiler that you are using the 'System' namespace

namespace Fundamentals //'namespace' is a special keyword that allows to separate the code in a meaninful manner
{
    class LearnThisFirst //Every single time you want to execute code, it needs to be inside of a Type, in this case, a Class
    {
        static void Main() //The 'Main' method that will execute first when running a console application
        {
            //Every Object you work with, has a type, in this case, it is a System.Int type, which we use the keyword 'int' to represent it
            int firstType = 3; //Your first Type
            
            Console.WriteLine("Hello World"); //Your first statement, this will output to console 'Hello World'

            int sum = 3 + 3;// '3+3' is an expression statement since it evaluates and creates a value

            /*When writting Console Applications, you can use 'Console.ReadLine()' statement to wait for User Input,
            then the CMD Window won't automatically close*/
            Console.ReadLine();

Garbage Collection

        [TestMethod]
        [ExpectedException(typeof(OutOfMemoryException))]
        public void OutOfMemory()
        {
            var csharpList = new List<CsharpClass>();

            for (var i = 0; i < 9000000; i++) //We increment the number of loops to create an OutOfMemoryException
            {
                var csharp = new CsharpClass(i.ToString(CultureInfo.InvariantCulture));
                csharpList.Add(csharp); 
            }
            //Performance is affected severely and program will never reach this point *On most commercial machines
            Assert.IsTrue(GetTotalCollections() < 403);
        }

        private static int GetTotalCollections() //How many GB collections ran in all generations
        {
            // 0 - When we first create an object, the references are placed in generation zero
            // 1 - If reference survives when the generatrion zero collection is placed, then the reference is placed on generation 1
            // 2 - If the references survive a collection on pass 1, they will be placed on generation 2
            return GC.CollectionCount(0) + GC.CollectionCount(1) + GC.CollectionCount(2); //We need to print the 3 generations of Garbage Collection
        }

Generics

        [TestMethod]
        public void DefaultKeyword() //The default keyword is used in a context where you do not know the Type at runtime
        {
            // default of Referenece Types is Null
            Assert.IsNull(ReturnDefault<ImplementsIDisposable>());
            // default of Value Numeric types is generally 0
            Assert.IsTrue(ReturnDefault<int>() == 0);
        }

        private static object CreateDisposer(Type type)
        {
            var implementsIDisposableType = typeof (Disposer<>); //This is an unbound generic type
            return Activator.CreateInstance(implementsIDisposableType.MakeGenericType(type)); //We get the type at runtime via the Type parameter
        }

        //You can specify the T of the returned value
        private static Disposer<T> CreateDisposer<T>() where T : IDisposable  //You can create Generic methods as well, with the same constrains as the class
        {
            var implementsIDisposableType = typeof(Disposer<>);
return Activator.CreateInstance(implementsIDisposableType.MakeGenericType(typeof(T))) as Disposer<T>;  //We get the type at runtime via the T Type
        }

        private static T ReturnDefault<T>()
        {
            return default(T);//This could be null or 0 *for most Int types
        }
    }
}

internal class Disposer<TDisposer> where TDisposer : IDisposable // You can set conditions on the Generic Type in order to perform more activities with the given instance at runtime
{
    public bool Dispose(TDisposer item)
    {
        item.Dispose();
        return true;
    }
}

internal class ImplementsIDisposable : IDisposable //This is a class that implements IDisposable
{
    public void Dispose() //This gets executed at runtime by the Disposer Class
    {
    }
}

Reflection: Code Generation

In this example we explain the use of Reflection and how to dynamically create code using C# / .Net

        [TestMethod]
        public void DynamicallyCreatingCode()
        {   //The method ‘GetMethod’ extracts the method information from Debug.Writeline 
            var methodInfo = typeof(Debug).GetMethod("WriteLine", new[] { typeof(string) }); 
            //We can specify the method signature by using a type of DynamicMethod
            var dynamicMethod = new DynamicMethod("DynamicMethod", typeof(void), new Type[] { }); 
            //We use 'GetILGenerator()' in order to create IL statements
            var ilGenerator = dynamicMethod.GetILGenerator();
            /*We use MS Intermediate Language calls to load the required information*/
            ilGenerator.Emit(OpCodes.Ldstr, "Test Dynamic Method");
            ilGenerator.Emit(OpCodes.Call, methodInfo);
            ilGenerator.Emit(OpCodes.Ret);//Return statement
            //We can create dynamic delegates and execute our method
            var action = (Action)dynamicMethod.CreateDelegate(typeof(Action)); 

            action();//Prints in Debug Console
            //This statement verifies that the action was created at runtime
            Assert.AreEqual(action.GetType(), typeof(Action));
            }

Run the Unit Tests

All Unit Tests are passing, you can modify the content of the tests in order to try different combinations or concepts.

Author

Martin Chavez

Continue Learning