Heim > Artikel > Backend-Entwicklung > Grundlagen der C#-Programmierung, Analyse generischer Methoden (Teil 1)
C# 2.0 führte die Funktion von Generika ein. Durch die Einführung von Generika wurde die Vitalität von C# bis zu einem gewissen Grad erheblich verbessert und kann einige Funktionen ausführen, die das Schreiben komplexer Codes in C# 1.0 erforderten. Aber als Entwickler habe ich eine Hassliebe zu Generika. Was mir gefällt, sind die leistungsstarken Funktionen und die Effizienzsteigerungen, die diese Funktion mit sich bringt. Was ich jedoch hasse, ist, dass Generika, wenn sie komplex sind, recht komplizierte Syntaxstrukturen aufweisen. .
Diese Komplexität ist nicht nur etwas für Anfänger, sondern auch eine Funktion, die für einige .NET-Entwickler mit Entwicklungserfahrung nicht einfach zu beherrschen ist.
Als nächstes werfen wir einen Blick auf die in C# 2.0 hinzugefügten Funktionen: Generika.
1. Überblick über die Grundfunktionen von Generika
In der tatsächlichen Projektentwicklung muss jede API nur verwendet werden Objekt als Die Verwendung von Parametertypen und Rückgabetypen kann irgendwann eine starke Typkonvertierung erfordern. Wenn es um die Konvertierung starker Typen geht, wird geschätzt, dass die erste Reaktion vieler Entwickler „Effizienz“ ist. Die Vor- und Nachteile der starken Typisierung hängen hauptsächlich von der Umgebung ab, in der der Benutzer sie verwendet Was das starke Tippen angeht, ist das Thema nicht der Schwerpunkt dieses Artikels und ich werde es nicht im Detail vorstellen.
Generika sind ein spezieller Mechanismus, der von CLR und C# bereitgestellt wird und eine andere Form der Code-Wiederverwendung unterstützt, nämlich die „Algorithmus-Wiederverwendung“. Generische Typen und Methoden implementieren die Parametrisierung von Typen und Methoden. Außerdem können Parameter den Benutzern mitteilen, welcher Typ verwendet werden soll.
Vorteile von Generika: bessere Überprüfung zur Kompilierungszeit, mehr Informationen, die direkt im Code ausgedrückt werden können, mehr IDE-Unterstützung, bessere Leistung. Manche Leute fragen sich vielleicht, warum Generika so viele Vorteile bringen. Die Verwendung einer regulären API, die nicht zwischen verschiedenen Typen unterscheiden kann, ist gleichbedeutend mit dem Zugriff auf diese API in einer dynamischen Umgebung.
CLR ermöglicht die Erstellung von generischen Referenz- und generischen Werttypen, jedoch nicht die Erstellung von generischen Aufzählungen, und die CLR ermöglicht die Erstellung von generischen Schnittstellen und generischen Delegaten, die CLR ermöglicht die Erstellung von Referenztypen, Werttypen oder Schnittstellen Definieren Sie generische Methoden. Beim Definieren eines generischen Typs oder einer generischen Methode werden alle für den Typ angegebenen Variablen (z. B. T) als Typparameter bezeichnet. (T ist ein Variablenname und T kann überall im Quellcode verwendet werden, wo ein Datentyp verwendet werden kann.) In C# werden generische Parametervariablen entweder zu T oder beginnen zumindest mit einem großen T.
2. Übersicht über generische Klassen, generische Schnittstellen und generische Delegaten
1. Generische Klassen
Generische Typen sind immer noch Typen und können daher von jedem Typ abgeleitet werden. Wenn Sie einen generischen Typ verwenden und Typargumente angeben, definieren Sie in der CLR ein neues Typobjekt, das von dem Typ abgeleitet ist, von dem der generische Typ abgeleitet ist.
Eine Methode, die generische Typparameter verwendet. Während der JIT-Kompilierung ruft die CLR die IL ab, ersetzt sie durch das angegebene Typargument und erstellt dann den entsprechenden nativen Code.
Wenn für einen generischen Typparameter keine Typargumente bereitgestellt werden, ist der generische Typ ungebunden. Wenn ein Typargument angegeben wird, ist der Typ ein konstruierter Typ.
Konstruierte Typen können offen oder geschlossen sein. Offene Typen enthalten auch eine Klasse, während geschlossene Typen nicht offen sind und jeder Teil des Typs explizit ist. Der gesamte Code wird tatsächlich im Kontext eines umschließenden konstruierten Typs ausgeführt.
Die Anwendung generischer Klassen in .NET erfolgt hauptsächlich in Sammlungsklassen, und die meisten Sammlungsklassen befinden sich in den Klassen System.Collections.Generic und System.Collections.ObjectModel. Im Folgenden finden Sie eine kurze Einführung in eine generische Sammlungsklasse:
(1).SynchronizedCollection: Stellt eine threadsichere Sammlung bereit, die Objekte des durch die generischen Parameter angegebenen Typs als Elemente enthält.
[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: Stellt eine Sammlung bereit, deren Elemente die als Schlüssel verwendeten Typen sind.
[__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 unterstützt die generische Delegation, die darauf abzielt, sicherzustellen, dass jeder Objekttyp typsicher an eine Rückrufmethode übergeben werden kann. Generische Delegaten ermöglichen die Übergabe einer untergeordneten Typinstanz an eine Rückrufmethode, ohne dass Boxing durchgeführt werden muss. Das Delegat-Timing stellt nur vier Methoden bereit: einen Konstruktor, eine Invlke-Methode, eine BeginInvoke-Methode und eine EndInvoke-Methode. Wenn Sie einen Delegate-Typ definieren, der Typparameter angibt, definiert der Compiler die Methode der Delegate-Klasse und ersetzt den Parametertyp und Werttyp der Methode durch die angegebenen Typparameter.
Das Obige ist der Inhalt der generischen Methodenanalyse (Teil 1) der C#-Programmiergrundlagen. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn).