Home > Article > Backend Development > Analysis of generic methods in C# programming basics (Part 1)
C#2.0 introduced the feature of generics. Due to the introduction of generics, the vitality of C# has been greatly enhanced to a certain extent. It can complete some functions that required writing complex code in C#1.0. But as a developer, I have a love-hate relationship with generics. What I love is its powerful functions and the efficiency improvements brought by this feature, but what I hate is that when generics are complex, they will present quite complicated syntax structures. .
This complexity is not only for beginners, but also a feature that is not easy to master for some .NET developers with development experience.
Next let’s take a look at the features added in C# 2.0: generics.
1. Overview of the basic characteristics of generics
In actual project development, any API only needs to use object as The use of parameter types and return types may involve strong type conversion at some point. When it comes to strong type conversion, it is estimated that the first reaction of many developers is "efficiency". The pros and cons of strong typing mainly depend on the environment in which the user uses it. There is no absolute bad thing or good thing in the world. Regarding strong typing, The issue is not the focus of this article and I will not introduce it in detail.
Generics are a special mechanism provided by the CLR and C# that support another form of code reuse, namely "algorithm reuse". Generics implement parameterization of types and methods. Generic types and methods can also let parameters tell users what type to use.
Benefits brought by generics: better compile-time checking, more information that can be directly expressed in the code, more IDE support, better performance. Some people may wonder why generics bring so many benefits. Using a regular API that cannot distinguish between different types is equivalent to accessing that API in a dynamic environment.
CLR allows the creation of generic references and generic value types, but does not allow the creation of generic enumerations, and the CLR allows the creation of generic interfaces and generic delegates. The CLR allows the creation of generic reference types, value types, or interfaces. Define generic methods. When defining a generic type or method, any variables (such as T) specified for the type are called type parameters. (T is a variable name, and T can be used anywhere in the source code that a data type can be used.) In C#, generic parameter variables either become T, or at least start with a capital T.
2. Overview of generic classes, generic interfaces and generic delegates
1. Generic classes
Generic types are still types, so they can be derived from any type . When you use a generic type and specify type arguments, you are defining a new type object in the CLR that is derived from the type from which the generic is derived.
One method of using generic type parameters During JIT compilation, the CLR obtains the IL, replaces it with the specified type argument, and then creates the appropriate native code.
If no type arguments are provided for a generic type parameter, then the generic type is unbound. If a type argument is specified, the type is a constructed type.
Constructed types can be open or closed. Open types also contain a class ixngcanshu, while closed types are not open and every part of the type is explicit. All code is actually executed within the context of an enclosing constructed type.
The application of generic classes in .NET is mainly in collection classes, and most collection classes are in the System.Collections.Generic and System.Collections.ObjectModel classes. The following is a brief introduction to a generic collection class:
(1).SynchronizedCollection: Provides a thread-safe collection that contains objects of the type specified by the generic parameters as elements.
[ComVisible(false)] public class SynchronizedCollection<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable { /// <summary> /// 初始化 <see cref="T:System.Collections.Generic.SynchronizedCollection`1"/> 类的新实例。 /// </summary> public SynchronizedCollection(); /// <summary> /// 通过用于对线程安全集合的访问进行同步的对象来初始化 <see cref="T:System.Collections.Generic.SynchronizedCollection`1"/> 类的新实例。 /// </summary> /// <param name="syncRoot">用于对线程安全集合的访问进行同步的对象。</param><exception cref="T:System.ArgumentNullException"> <paramref name="syncRoot"/> 为 null。</exception> public SynchronizedCollection(object syncRoot); /// <summary> /// 使用指定的可枚举元素列表和用于对线程安全集合的访问进行同步的对象来初始化 <see cref="T:System.Collections.Generic.SynchronizedCollection`1"/> 类的新实例。 /// </summary> /// <param name="syncRoot">用于对线程安全集合的访问进行同步的对象。</param> <param name="list">用于初始化线程安全集合的元素的 <see cref="T:System.Collections.Generic.IEnumerable`1"/> 集合。</param> <exception cref="T:System.ArgumentNullException"><paramref name="syncRoot"/> 或 <paramref name="list"/> 为 null。</exception> public SynchronizedCollection(object syncRoot, IEnumerable<T> list); /// <summary> /// 使用指定的元素数组和用于对线程安全集合的访问进行同步的对象来初始化 <see cref="T:System.Collections.Generic.SynchronizedCollection`1"/> 类的新实例。 /// </summary> /// <param name="syncRoot">用于对线程安全集合的访问进行同步的对象。</param> <param name="list">用于初始化线程安全集合的 <paramref name="T"/> 类型元素的 <see cref="T:System.Array"/>。</param> <exception cref="T:System.ArgumentNullException"><paramref name="syncRoot"/> 或 <paramref name="list"/> 为 null。</exception> public SynchronizedCollection(object syncRoot, params T[] list); /// <summary> /// 将项添加到线程安全只读集合中。 /// </summary> /// <param name="item">要添加到集合的元素。</param> <exception cref="T:System.ArgumentException">设置的值为 null,或者不是集合的正确泛型类型 <paramref name="T"/>。</exception> public void Add(T item); /// <summary> /// 从集合中移除所有项。 /// </summary> public void Clear(); /// <summary> /// 从特定索引处开始,将集合中的元素复制到指定的数组。 /// </summary> /// <param name="array">从集合中复制的 <paramref name="T "/>类型元素的目标 <see cref="T:System.Array"/>。</param> <param name="index">复制开始时所在的数组中的从零开始的索引。</param> public void CopyTo(T[] array, int index); /// <summary> /// 确定集合是否包含具有特定值的元素。 /// </summary> /// /// <returns> /// 如果在集合中找到元素值,则为 true;否则为 false。 /// </returns> /// <param name="item">要在集合中定位的对象。</param> <exception cref="T:System.ArgumentException">设置的值为 null,或者不是集合的正确泛型类型 <paramref name="T"/>。</exception> public bool Contains(T item); /// <summary> /// 返回一个循环访问同步集合的枚举数。 /// </summary> /// /// <returns> /// 一个 <see cref="T:System.Collections.Generic.IEnumerator`1"/>,用于访问集合中存储的类型的对象。 /// </returns> public IEnumerator<T> GetEnumerator(); /// <summary> /// 返回某个值在集合中的第一个匹配项的索引。 /// </summary> /// /// <returns> /// 该值在集合中的第一个匹配项的从零开始的索引。 /// </returns> /// <param name="item">从集合中移除所有项。</param><exception cref="T:System.ArgumentException">设置的值为 null,或者不是集合的正确泛型类型 <paramref name="T"/>。</exception> public int IndexOf(T item); /// <summary> /// 将一项插入集合中的指定索引处。 /// </summary> /// <param name="index">要从集合中检索的元素的从零开始的索引。</param><param name="item">要作为元素插入到集合中的对象。</param> <exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小于零或大于集合中的项数。</exception> <exception cref="T:System.ArgumentException">设置的值为 null,或者不是集合的正确泛型类型 <paramref name="T"/>。</exception> public void Insert(int index, T item); /// <summary> /// 从集合中移除指定项的第一个匹配项。 /// </summary> /// /// <returns> /// 如果从集合中成功移除了项,则为 true;否则为 false。 /// </returns> /// <param name="item">要从集合中移除的对象。</param> public bool Remove(T item); /// <summary> /// 从集合中移除指定索引处的项。 /// </summary> /// <param name="index">要从集合中检索的元素的从零开始的索引。</param> <exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小于零或大于集合中的项数。</exception> public void RemoveAt(int index); /// <summary> /// 从集合中移除所有项。 /// </summary> protected virtual void ClearItems(); /// <summary> /// 将一项插入集合中的指定索引处。 /// </summary> /// <param name="index">集合中从零开始的索引,在此处插入对象。</param><param name="item">要插入到集合中的对象。</param> <exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小于零或大于集合中的项数。</exception> <exception cref="T:System.ArgumentException">设置的值为 null,或者不是集合的正确泛型类型 <paramref name="T"/>。</exception> protected virtual void InsertItem(int index, T item); /// <summary> /// 从集合中移除指定 <paramref name="index"/> 处的项。 /// </summary> /// <param name="index">要从集合中检索的元素的从零开始的索引。</param> <exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小于零或大于集合中的项数。</exception> protected virtual void RemoveItem(int index); /// <summary> /// 使用另一项替换指定索引处的项。 /// </summary> /// <param name="index">要替换的对象的从零开始的索引。</param><param name="item">要替换的对象。</param> <exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小于零或大于集合中的项数。</exception> protected virtual void SetItem(int index, T item); /// <summary> /// 返回一个循环访问同步集合的枚举数。 /// </summary> /// /// <returns> /// 一个 <see cref="T:System.Collections.Generic.IEnumerator`1"/>,用于访问集合中存储的类型的对象。 /// </returns> IEnumerator IEnumerable.GetEnumerator(); /// <summary> /// 从特定索引处开始,将集合中的元素复制到指定的数组。 /// </summary> /// <param name="array">从集合中复制的 <paramref name="T"/> 类型元素的目标 <see cref="T:System.Array"/>。</param> <param name="index">复制开始时所在的数组中的从零开始的索引。</param> void ICollection.CopyTo(Array array, int index); /// <summary> /// 向集合中添加一个元素。 /// </summary> /// /// <returns> /// 新元素的插入位置。 /// </returns> /// <param name="value">要添加到集合中的对象。</param> int IList.Add(object value); /// <summary> /// 确定集合是否包含具有特定值的元素。 /// </summary> /// <returns> /// 如果在集合中找到元素 <paramref name="value"/>,则为 true;否则为 false。 /// </returns> /// <param name="value">要在集合中定位的对象。</param><exception cref="T:System.ArgumentException"><paramref name="value"/> 不是集合所含类型的对象。</exception> bool IList.Contains(object value); /// <summary> /// 确定集合中某个元素的从零开始的索引。 /// </summary> /// /// <returns> /// 如果在集合中找到,则为 <paramref name="value"/> 的索引;否则为 -1。 /// </returns> /// <param name="value">集合中要确定其索引的元素。</param> int IList.IndexOf(object value); /// <summary> /// 将某个对象插入到集合中的指定索引处。 /// </summary> /// <param name="index">从零开始的索引,将在该位置插入 <paramref name="value"/>。</param><param name="value">要在集合中插入的对象。</param> <exception cref="T:System.ArgumentOutOfRangeException">指定的 <paramref name="index"/> 小于零或大于集合中的项数。</exception> <exception cref="T:System.ArgumentException">设置的 <paramref name="value"/> 为 null,或者不是集合的正确泛型类型 <paramref name="T"/>。</exception> void IList.Insert(int index, object value); /// <summary> /// 从集合中移除作为元素的指定对象的第一个匹配项。 /// </summary> /// <param name="value">要从集合中移除的对象。</param> void IList.Remove(object value); }
( 2).KeyedByTypeCollection: Provides a collection whose items are the types used as keys.
[__DynamicallyInvokable] public class KeyedByTypeCollection<TItem> : KeyedCollection<Type, TItem> { /// <summary> /// 初始化 <see cref="T:System.Collections.Generic.KeyedByTypeCollection`1"/> 类的新实例。 /// </summary> public KeyedByTypeCollection(); /// <summary> /// 根据指定的对象枚举初始化 <see cref="T:System.Collections.Generic.KeyedByTypeCollection`1"/> 类的新实例。 /// </summary> /// <param name="items">泛型类型 <see cref="T:System.Object"/> 的 <see cref="T:System.Collections.Generic.IEnumerable`1"/>,用于初始化集合。</param> <exception cref="T:System.ArgumentNullException"><paramref name="items"/> 为 null。</exception> public KeyedByTypeCollection(IEnumerable<TItem> items); /// <summary> /// 返回集合中第一个具有指定类型的项。 /// </summary> /// /// <returns> /// 如果为引用类型,则返回类型 <paramref name="T"/> 的对象;如果为值类型,则返回类型 <paramref name="T"/> 的值。 如果集合中不包含类型 <paramref name="T"/> 的对象,则返回类型的默认值:如果是引用类型,默认值为 null;如果是值类型,默认值为 0。 /// </returns> /// <typeparam name="T">要在集合中查找的项的类型。</typeparam> [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] public T Find<T>(); /// <summary> /// 从集合中移除具有指定类型的对象。 /// </summary> /// /// <returns> /// 从集合中移除的对象。 /// </returns> /// <typeparam name="T">要从集合中移除的项的类型。</typeparam> [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] public T Remove<T>(); /// <summary> /// 返回 <see cref="T:System.Collections.Generic.KeyedByTypeCollection`1"/> 中包含的类型 <paramref name="T"/> 的对象的集合。 /// </summary> /// /// <returns> /// 一个类型 <paramref name="T"/> 的 <see cref="T:System.Collections.ObjectModel.Collection`1"/>,包含来自原始集合的类型 <paramref name="T"/> 的对象。 /// </returns> /// <typeparam name="T">要在集合中查找的项的类型。</typeparam> [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] public Collection<T> FindAll<T>(); /// <summary> /// 从集合中移除所有具有指定类型的元素。 /// </summary> /// /// <returns> /// <see cref="T:System.Collections.ObjectModel.Collection`1"/>,包含来自原始集合的类型 <paramref name="T"/> 的对象。 /// </returns> /// <typeparam name="T">要从集合中移除的项的类型。</typeparam> [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] public Collection<T> RemoveAll<T>(); /// <summary> /// 获取集合中包含的某个项的类型。 /// </summary> /// /// <returns> /// 集合中指定的 <paramref name="item"/> 的类型。 /// </returns> /// <param name="item">集合中要检索其类型的项。</param><exception cref="T:System.ArgumentNullException"><paramref name="item"/> 为 null。</exception> [__DynamicallyInvokable] protected override Type GetKeyForItem(TItem item); /// <summary> /// 在集合中的特定位置插入一个元素。 /// </summary> /// <param name="index">从零开始的索引,应在该位置插入 <paramref name="item"/>。</param><param name="item">要在集合中插入的对象。</param> <exception cref="T:System.ArgumentNullException"><paramref name="item"/> 为 null。</exception> [__DynamicallyInvokable] protected override void InsertItem(int index, TItem item); /// <summary> /// 使用一个新对象替换指定索引处的项。 /// </summary> /// <param name="index">要替换的 <paramref name="item"/> 的从零开始的索引。</param><param name="item">要添加到集合中的对象。</param> <exception cref="T:System.ArgumentNullException"><paramref name="item"/> 为 null。</exception> [__DynamicallyInvokable] protected override void SetItem(int index, TItem item); }
CLR supports generic delegation to ensure that any type of object can be passed to a callback method in a type-safe manner. Generic delegates allow a child type instance to be passed to a callback method without performing any boxing. The delegate timing provides only 4 methods: a constructor, an Invlke method, a BeginInvoke method and an EndInvoke method. If you define a delegate type that specifies type parameters, the compiler will define the method of the delegate class and replace the method's parameter type and value type with the specified type parameters.
The above is the content of Generic Method Analysis (Part 1) of C# Programming Basics. For more related content, please pay attention to the PHP Chinese website (www.php.cn)!