Tuesday 13 June 2017

What are C# Generics?

So I don’t forget what C# Generics are, I created this memo + code (or memode).

Generics templatise your code maximising reuse, keeping it strongly typed and performant. Any type can be generic, but it is advised to use the new generic collection classes System.Collections.Generic inso System.Collections. You can use runtime reflection to get info about generic types.

Here is some code using generics on different types.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GenericsTest
{


    // Generic array definition. 
    public class MyGenericArray<X>
    {

        private X[] Array; 

        public MyGenericArray(int Size)
        {
            Array = new X[Size + 1];
        }

        public X GetItem(int Index)
        {
            return Array[Index];
        }

        public void SetItem(int Index, X Value)
        {
            Array[Index] = Value; 
        }

    }



    // Generic method definition. 
    public static class GenericMethod<T>
    {
        public static void Swap(ref T Left, ref T Right)
        {
            T Temp = Left;
            Left = Right;
            Right = Temp; 
        }
    }



    

    // Define test interface. 
    public interface ITest
    {
        int GetPropertyValue(); 
    } 

    // Inherit from ITest interface. 
    public class MyClassTest : ITest
    {

        private int MyProperty { get; set; }

        public MyClassTest(int InitialValue)
        {
            MyProperty = InitialValue;
        }


        // To prove our generic swap function works, 
        // we will nest a class within a class. 
        // The inner class has a method to get the property. 
        public int GetPropertyValue()
        {

            // Initialise. 
            Value MyValue = new Value(MyProperty);

            MyProperty = MyValue.GetPropertyValue();

            return MyProperty; 
            
        }


        // Finer precision of interface. 
        public interface IValue
        {
            int GetPropertyValue(); 
        }


        // Inherit from IValue interface.  
        public class Value : IValue
        {

            private int MyProperty { get; set; }

            public Value(int Value)
            {
                MyProperty = Value; 
            }

            public int GetPropertyValue()
            {
                return MyProperty; 
            }

        }

    }






    // Define test interface that contains another interface. 
    public interface ITestInterface : ITestAnotherInterface 
    {
        int MyProperty { get; set; } 
    }

    public interface ITestAnotherInterface
    {
        int MyPropertyAnother { get; set; }
    } 

    // Declare test class using multiple interfaces. 
    public class MultiInterface : ITestInterface
    {

        private int PropertyBase;
        private int PropertyAnother;

        public int MyProperty
        {
            get { return PropertyBase;  }
            set { PropertyBase = value;  }
        }

        public int MyPropertyAnother
        {
            get { return PropertyAnother;  }
            set { PropertyAnother = value;  }
        }


    } 



    // Define test interface. 
    public interface ITestOddEven {
        int GetValue(); 
    }

    // Declare test classes. 
    public class OddTest : ITestOddEven
    {
        private const int Even = 2;
        private const int Odd = 3;
        
        public int GetValue()
        {
            return Odd; 
        }

    } 

    public class EvenTest : ITestOddEven
    {
        private const int Even = 2;
        private const int Odd = 3;

        public int GetValue()
        {
            return Even;
        }
    }




    // Define test delegate. 
    public delegate int TestGetValue();





    class Program
    {



        static void Main(string[] args)
        {


            Random Generate = new Random();

            string Characters =
                "$%#@!*abcdefghijklmnopqrstuvwxyz" +
                "1234567890?;:ABCDEFGHIJKLMNOPQRSTUVWXYZ^&";



            // Create generic int array. 
            MyGenericArray<int> IntArray = new MyGenericArray<int>(5);

            // Set values. 
            for (int Index = 0; Index < 5; Index++)
                IntArray.SetItem(Index, Generate.Next(1, 9999999));

            // Get values. 
            for (int Index = 0; Index < 5; Index++)
                Console.WriteLine(IntArray.GetItem(Index));





            // Create generic char array. 
            MyGenericArray<char> CharArray = new MyGenericArray<char>(5);

            // Set values. 
            for (int Index = 0; Index < 5; Index++)
                CharArray.SetItem(Index, Characters[Generate.Next(0, Characters.Length - 1)]);

            // Get values. 
            for (int Index = 0; Index < 5; Index++)
                Console.WriteLine(CharArray.GetItem(Index));





            // Create generic string array. 
            MyGenericArray<string> StringArray = new MyGenericArray<string>(5);

            // Set values. 
            for (int Index = 0; Index < 5; Index++)
            {

                string Value = "";

                for (int StringIndex = 0; StringIndex < 10; StringIndex++)
                    Value += Characters[Generate.Next(0, Characters.Length - 1)];

                StringArray.SetItem(Index, Value);

            }

            // Get values. 
            for (int Index = 0; Index < 5; Index++)
                Console.WriteLine(StringArray.GetItem(Index));





            // Create generic double array. 
            MyGenericArray<double> DoubleArray = new MyGenericArray<double>(5);

            // Set values. 
            for (int Index = 0; Index < 5; Index++)
                DoubleArray.SetItem(Index, Math.Round(Generate.NextDouble() *
                    Generate.Next(1, 1000), 2));

            // Get values. 
            for (int Index = 0; Index < 5; Index++)
                Console.WriteLine(DoubleArray.GetItem(Index));





            // Create generic byte array. 
            MyGenericArray<byte[]> ByteArray = new MyGenericArray<byte[]>(5);

            // Set values. 
            for (int Index = 0; Index < 5; Index++)
            {
                byte[] ByteBuffer = new byte[10];
                Generate.NextBytes(ByteBuffer);
                ByteArray.SetItem(Index, ByteBuffer);
            }

            // Get values. 
            Console.WriteLine("Getting byte array values:");
            for (int Index = 0; Index < 5; Index++)
            {
                Console.WriteLine(ByteArray.GetItem(Index).GetValue(0));
            }

            // Get values. 
            Console.WriteLine("Getting byte array values:");
            for (int Index = 0; Index < 5; Index++)
            {
                Console.WriteLine(ByteArray.GetItem(Index).GetValue(9));
            }





            // Byte test. 
            Byte Test = new Byte();
            Test = 0x99;
            Console.WriteLine("Byte test = {0}", Test.ToString());





            // Generic methods. 


            int A = 1, B = 2;
            // Before. 
            Console.WriteLine("Before");
            Console.WriteLine("A = {0}, B = {1}", A, B);
            // Swap. 
            GenericMethod<int>.Swap(ref A, ref B);
            // After. 
            Console.WriteLine("After");
            Console.WriteLine("A = {0}, B = {1}", A, B);


            char X = 'x', Y = 'y';
            // Before. 
            Console.WriteLine("Before");
            Console.WriteLine("X = {0}, Y = {1}", X, Y);

            GenericMethod<char>.Swap(ref X, ref Y);
            // After. 
            Console.WriteLine("After");
            Console.WriteLine("X = {0}, Y = {1}", X, Y);




            // Generate List string array. 
            List<string> MyStringList = new List<string>(4);
            // Populate. 
            for (int ItemIndex = 0; ItemIndex < 4; ItemIndex++)
            {
                var Value = "";

                for (int Index = 0; Index < 3; Index++)
                    Value += Characters[Generate.Next(0, Characters.Length - 1)];

                MyStringList.Add(Value);
            }
            // Before. 
            Console.WriteLine("Before");
            foreach (var ListItem in MyStringList.Cast<object>().Select((x, i) => new { Item = x, Index = i }))
                Console.WriteLine("Item[{0}] = {1}", ListItem.Index, ListItem.Item);

            // Swap all items. 
            //foreach (var ListItem in MyStringList.Cast<object>().Select((x, i) => new { Item = x, Index = i })) ; 
            for (int Index = 0; Index < 4; Index++)
            {

                // End reached, nothing to swap.    
                if (Index == MyStringList.Count() - 1)
                    continue;

                var Current = MyStringList[Index];
                var Next = MyStringList[Index + 1];

                GenericMethod<string>.Swap(ref Current, ref Next);

                MyStringList[Index] = Current;
                MyStringList[Index + 1] = Next;

            }

            // After. 
            Console.WriteLine("After");
            foreach (var ListItem in MyStringList.Cast<object>().Select((x, i) => new { Item = x, Index = i }))
                Console.WriteLine("Item[{0}] = {1}", ListItem.Index, ListItem.Item);




            // Create test class instances. 
            MyClassTest TestClass1 = new MyClassTest(5);
            MyClassTest TestClass2 = new MyClassTest(10);



            // MyClassTest[] TestClasses = new MyClassTest[2];  
            //{
            //    new MyClassTest(), 
            //    new MyClassTest()
            //};
            //TestClasses[0] = TestClass1;
            //TestClasses[1] = TestClass2;


            //Console.WriteLine(nameof(TestClass1));
            //Console.WriteLine(nameof(TestClass2));


            // Before. 
            Console.WriteLine("Before");
            Console.WriteLine(
                "TestClass1.GetPropertyValue() = {0}, TestClass2.GetPropertyValue() = {1} ",
                TestClass1.GetPropertyValue(), TestClass2.GetPropertyValue());

            // Swap. 
            GenericMethod<MyClassTest>.Swap(ref TestClass1, ref TestClass2);

            // After. 
            Console.WriteLine("After");
            Console.WriteLine(
                "TestClass1.GetPropertyValue() = {0}, TestClass2.GetPropertyValue() = {1} ",
                TestClass1.GetPropertyValue(), TestClass2.GetPropertyValue());





            // Create test classes with multiple interfaces. 
            MultiInterface MultiInterfaceTest1 = new MultiInterface();
            MultiInterfaceTest1.MyProperty = 1;
            MultiInterfaceTest1.MyPropertyAnother = 2;

            MultiInterface MultiInterfaceTest2 = new MultiInterface();
            MultiInterfaceTest2.MyProperty = 3;
            MultiInterfaceTest2.MyPropertyAnother = 4;

            // Before. 
            Console.WriteLine("Before");
            Console.WriteLine("MultiInterfaceTest1.MyProperty = {0}", MultiInterfaceTest1.MyProperty);
            Console.WriteLine("MultiInterfaceTest1.MyPropertyAnother = {0}", MultiInterfaceTest1.MyPropertyAnother);
            Console.WriteLine("MultiInterfaceTest2.MyProperty = {0}", MultiInterfaceTest2.MyProperty);
            Console.WriteLine("MultiInterfaceTest2.MyPropertyAnother = {0}", MultiInterfaceTest2.MyPropertyAnother);

            // Swap interfaces. 
            GenericMethod<MultiInterface>.Swap(ref MultiInterfaceTest1, ref MultiInterfaceTest2);

            // After. 
            Console.WriteLine("After");
            Console.WriteLine("MultiInterfaceTest1.MyProperty = {0}", MultiInterfaceTest1.MyProperty);
            Console.WriteLine("MultiInterfaceTest1.MyPropertyAnother = {0}", MultiInterfaceTest1.MyPropertyAnother);
            Console.WriteLine("MultiInterfaceTest2.MyProperty = {0}", MultiInterfaceTest2.MyProperty);
            Console.WriteLine("MultiInterfaceTest2.MyPropertyAnother = {0}", MultiInterfaceTest2.MyPropertyAnother);




            // Swap values in individual interfaces. 
            Console.WriteLine("Swapping values in individual interfaces ... ");
            int BaseValue = MultiInterfaceTest1.MyProperty;
            int AnotherValue = MultiInterfaceTest1.MyPropertyAnother;
            GenericMethod<int>.Swap(ref BaseValue, ref AnotherValue);
            MultiInterfaceTest1.MyProperty = BaseValue;
            MultiInterfaceTest1.MyPropertyAnother = AnotherValue;

            BaseValue = MultiInterfaceTest2.MyProperty;
            AnotherValue = MultiInterfaceTest2.MyPropertyAnother;
            GenericMethod<int>.Swap(ref BaseValue, ref AnotherValue);
            MultiInterfaceTest2.MyProperty = BaseValue;
            MultiInterfaceTest2.MyPropertyAnother = AnotherValue;

            // After. 
            Console.WriteLine("After");
            Console.WriteLine("MultiInterfaceTest1.MyProperty = {0}", MultiInterfaceTest1.MyProperty);
            Console.WriteLine("MultiInterfaceTest1.MyPropertyAnother = {0}", MultiInterfaceTest1.MyPropertyAnother);
            Console.WriteLine("MultiInterfaceTest2.MyProperty = {0}", MultiInterfaceTest2.MyProperty);
            Console.WriteLine("MultiInterfaceTest2.MyPropertyAnother = {0}", MultiInterfaceTest2.MyPropertyAnother);




            // Create interface variables. 
            ITestOddEven TestOddEven1 = new OddTest();
            ITestOddEven TestOddEven2 = new EvenTest();

            // Before. 
            Console.WriteLine("Before");
            Console.WriteLine("TestOddEven1.GetValue() = {0}", TestOddEven1.GetValue());
            Console.WriteLine("TestOddEven1.GetValue() = {0}", TestOddEven2.GetValue());

            // Swap out the GetValue methods by interface references. 
            GenericMethod<ITestOddEven>.Swap(ref TestOddEven1, ref TestOddEven2);

            // After. 
            Console.WriteLine("After");
            Console.WriteLine("TestOddEven1.GetValue() = {0}", TestOddEven1.GetValue());
            Console.WriteLine("TestOddEven1.GetValue() = {0}", TestOddEven2.GetValue());



            // Create delegates. 
            TestGetValue TestDelegateEven = TestOddEven1.GetValue;
            TestGetValue TestDelegateOdd = TestOddEven2.GetValue;

            // Before. 
            Console.WriteLine("Before");
            Console.WriteLine("TestDelegateEven = {0}", TestDelegateEven());
            Console.WriteLine("TestDelegateOdd = {0}", TestDelegateOdd());

            // Swap around method references using delegates. 
            GenericMethod<TestGetValue>.Swap(ref TestDelegateEven, ref TestDelegateOdd);

            // After. 
            Console.WriteLine("After");
            Console.WriteLine("TestDelegateEven = {0}", TestDelegateEven());
            Console.WriteLine("TestDelegateOdd = {0}", TestDelegateOdd());






            // Create delegates to test method parameters. 
            NumberFunction<int> FunctionTestAdd = new NumberFunction<int>(Add);
            NumberFunction<int> FunctionTestMultiply = new NumberFunction<int>(Multiply);

            // Before. 
            Console.WriteLine("Before");
            Console.WriteLine("FunctionTestAdd(2) = {0}", FunctionTestAdd(2));
            Console.WriteLine("FunctionTestMultiply(4) = {0}", FunctionTestMultiply(4));

            // Swap delegate references to methods. 
            GenericMethod<NumberFunction<int>>.Swap(ref FunctionTestAdd, ref FunctionTestMultiply);
            Console.WriteLine("Swapping delegate method references ...");
            Console.WriteLine("FunctionTestAdd(3) = {0}", FunctionTestAdd(3));
            Console.WriteLine("FunctionTestMultiply(1) = {0}", FunctionTestMultiply(1)); 







            Console.ReadLine();

        }


        // Define test generic delegate. 
        public delegate T NumberFunction<T>(T Value);

        // Define test methods for the delegate.  
        private static int Total = 0;

        public static int Add(int Number)
        {
            return Total += Number;
        }

        public static int Multiply(int Number)
        {
            return Total *= Number;
        }


    }

}

No comments:

Post a Comment