C# generic understanding

C# generic understanding

"Generics is a special mechanism provided by c# programming language version 2.0 and above and CLR. It supports another form of code reuse, namely 'algorithm reuse'.". (From<CLR via C#>)
Generic implements the construction of generic classes, methods, interfaces and other unspecified data types, which are not specified until they are used. It perfectly embodies the design idea - delay declaration: delay everything that can be delayed.
Generics is not a simple syntax sugar. Its implementation depends on the upgrade support of the. NET framework.

Namespace: using System.Collections.Generic

1, Generic application scenarios

        static void Main(string[] args)
        {
            Printf("Hello~");
            Printf(1);
            Printf(false);
            Console.ReadKey();
        }

        private static void Printf(string input)
        {
            Console.WriteLine("Input is:{0},{1}" ,input,input.GetType());
        }

        private static void Printf(int input)
        {
            Console.WriteLine("Input is:{0},{1}", input, input.GetType());
        }

        private static void Printf(bool input)
        {
            Console.WriteLine("Input is:{0},{1}", input, input.GetType());
        }

It can be seen that the difference between the above three methods is that the incoming parameter types are different, and the functions implemented in the methods are the same. At this time, we have two methods: one is to declare the incoming parameter type as object, and the other is to use generics.
Why is object not recommended?

        static void Main(string[] args)
        {
            //Normal output
            object input = "Hello~";
            Printf(input);

            //Cast, no error at compile time, but error at run time
            int nStr = (int)input;
            Printf(nStr);
        }

        private static void Printf(object input)
        {
            Console.WriteLine("Input is:{0},{1}" ,input,input.GetType());
        }

It can be seen from this that the use of objects requires forced conversion. The boxing and unpacking of forced conversion will cause a lot of performance loss. In addition to performance, objects cannot ensure type safety. Forced conversion tells the compiler that such conversion is safe. If the conversion fails at runtime, data loss will be caused.

2, Advantages of generics

1. Source code protection;
2. Type safety;
3. Clearer code and easier maintenance performance
4. Better performance.

The following code shows the performance difference between generic List and non generic ArrayList.

using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            const Int32 count = 100000000;
            using (new MyTimer("List<Int32>"))
            {
                List<Int32> l = new List<int>();
                for (Int32 i = 0; i < count; i++)
                {
                    l.Add(i);  //No packing
                    Int32 n = l[i];   //No unpacking
                }
                l = null;
            }

            using (new MyTimer("ArrayList"))
            {
                ArrayList array = new ArrayList();
                for (Int32 i = 0; i < count; i++)
                {
                    array.Add(i); //Packing occurs
                    Int32 n = (Int32)array[i]; //Unpacking occurs
                }
            }
            Console.ReadKey();
        }
    }

    /// <summary>
    ///Custom class used to calculate performance time
    /// </summary>
    internal sealed class MyTimer : IDisposable
    {
        private Stopwatch stopwatch;

        private string text;
        private Int32 collectionCount;

        public MyTimer(string _text)
        {
            PrepareForAction();
            text = _text;
            collectionCount = GC.CollectionCount(0);

            stopwatch = Stopwatch.StartNew();
        }

        public void Dispose()
        {
            Console.WriteLine("{0} (GCs={1,3}) {2}", stopwatch.Elapsed, GC.CollectionCount(0) - collectionCount, text);
        }

        /// <summary>
        ///Garbage collection
        /// </summary>
        private static void PrepareForAction()
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
        }
    }
}


It can be seen from the running results that the generic List algorithm is much faster than the non generic ArrayList when operating the value type, with a difference of 0.96 and 7.6 seconds. In addition, the operation of non generic causes a large number of packing and unpacking, and 388 garbage collection times are required at last, while the generic algorithm only needs 8 times.
However, for reference type data, the difference is not obvious, and the garbage collection times and time are almost the same (you can test yourself)

3, Several applications of generics
Generic applications include generic collection classes, generic interfaces, and generic methods.

/// <summary>
        ///Generic method
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tParameter"></param>
        public static void Show<T>(T tParameter)
        {
            Console.WriteLine("This is parameter={0},type={1}",tParameter.GetType().Name, tParameter.ToString());
        }
/// <summary>
    ///Generic class
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class GenericClass<T>
    {
        public T _T;
    }
/// <summary>
    ///Generic interface
    /// </summary>
    public interface IGenericInterface<T>
    {
        //Return value of generic type
        T GetT(T t);
    }
public delegate void SayHi<T>(T t);//generic delegate 

Although you can customize generic delegates, it is best to use the delegates that come with the framework.

4, Generic constraints
Generic constraint format: use the where keyword
Meaning of generic constraint: ensure that the passed type parameters meet certain conditions, and verify the passed parameters at the compilation stage

typeConstraint formatExample
Interface constraintsT: < interface name >public class MyGenericClass where T:IComparable { }
Base class constraintT: < base class name >class MyClassy<T, U> where T : class
Reference constraintT: classpublic class BaseAccess where T : class{}
Value constraintT: structpublic class MyClass9 where T : struct { }
constructor constraint T: new()public class MyGenericClass where T: IComparable, new(){T item = new T(); }
naked type constraint T: Uclass List{void Add(List items) where U : T { }}

Generic constraint considerations:
1. Multiple constraints
It is not possible to add both struct and class constraints
It is not possible to add multiple base class constraints
Constraints are and relationships, and constraints of or relationships cannot be added
Constructor constraint must be last
Constructor constraints can only indicate parameterless constructors
Constraints do not inherit

2. Multiple parameters
For a generic class keyValue < TKey,TValue >, which represents the "key value pair" relationship, this class has two generic parameters TKey,TValue, for which constraints should be added.

Tags: C#

Posted on Wed, 22 Sep 2021 21:37:19 -0400 by jasonmills58