In the process of project development using an object-oriented language, more "inheritance" features will be used, but not all scenarios are suitable for using the "inheritance" features, and there are also many mentions in some basic principles of the design pattern.
The problem brought about by the use of inherited features: the inheritance relationship of the object is actually defined at compile time, so the implementation inherited from the parent class cannot be changed at runtime. The implementation of a subclass has a very close dependency with its parent class, so that any changes in the implementation of the parent class will inevitably lead to changes in the subclass. When you need to reuse a subclass, if the inherited implementation is not suitable for solving a new problem, the parent class must override it or be replaced by another more suitable class. This dependency limits flexibility and ultimately limits reusability. In the alternative to inheritance features, the principle of synthesis/aggregation and reuse is mostly adopted. The principle of "synthesis/aggregation and reuse": try to use synthesis/aggregation and try not to use class inheritance.
If objects in new types should carry details about additional behavior, they may sometimes be less suitable when using inheritance features, such as when dealing with referential types, seal classes, or interfaces. When facing these requirements, we sometimes write some static classes that contain some static methods. But too many static methods can cause additional unnecessary overhead.
1. Overview of extension methods:
Faced with the above problems related to "inheritance" and when facing some project needs, the way we need to solve these problems is the "extend method". "Extended methods" were introduced in C# 3.0, which not only had the advantages of static methods, but also improved the readability of the code that calls them. When using an extension method, you can call a static method like an instance method.
1. Basic principles of extension method:
(1).C# only supports extension methods, and does not support extension properties, extension events, extension operators, etc.
(2). The extension method (the first parameter is preceded by this method) must be declared in a non-generic static class. The extension method must have one parameter, and only the first parameter is marked with this.
(3). When the C# compiler looks for extension methods in static classes, these static classes themselves must have file scope.
(4).C# compilation requires "import" extension method. (Static methods can be named arbitrarily. When the C# compiler is looking for methods, it takes time to search. It needs to check all static classes in the file scope and scan all their static methods to find a match)
(5). Multiple static classes can define the same extension method.
(6). When using an extension method to extend a type, the derived type is also extended.
2. Extension method declaration:
(1). Must be in a non-necked, non-generic static class (so it must be a static method)
(2). There is at least one parameter.
(3). The first parameter must be prefixed with this keyword.
(4). The first parameter cannot have any other modifiers (such as ref or out).
(5). The type of the first parameter cannot be a pointer type.
In the above two classification descriptions, a brief introduction is given to the basic characteristics and declaration methods of the extension method. The usage methods of the extension method will be displayed in the code examples below. I will not explain them again.
2. Analysis of the principle of extension method:
"Extension method" is a unique method in C#. The ExtensionAttribute attribute will be used in the extension method.
Once C# uses this keyword to mark the first parameter of a static method, the compiler will internally apply a customized attribute to the method. This attribute will be persistently stored in the metadata of the final generated file. This attribute is in the dll assembly.
As long as any static class contains at least one extension method, this attribute will also be used in its metadata. Any assembly contains at least one static class that meets the above characteristics, and its metadata will also be used in its metadata. If the code uses an instance method that does not exist, the compiler will quickly scan all the referenced assembly to determine which of them contain extension methods. Then, in this assembly, you can scan for static classes containing extension methods.
If two classes in the same namespace contain methods with the same extension type, there is no way to use only the extension methods in one of the classes. In order to use a type through a simple name (without a namespace prefix), you can import all the namespaces of the type, but when doing this, you have no way to prevent the extension methods in that namespace from being imported.
Three..NET3.5 extension methods Enumerable and Queryable:
In the framework, the biggest purpose of the extension method is to serve LINQ. The framework provides auxiliary extension methods, including Enumerable and Queryable classes located in the namespace. Most Enumerable extensions are IEnumerable<T>, and most Queryable extensions are IQueryable<T>.
Common methods in the class:
(1).Range(): One parameter is the starting number, and the other is the result number to be generated.
public static IEnumerable<int> Range(int start, int count) { long max = ((long)start) + count - 1; if (count < 0 || max > ) throw ("count"); return RangeIterator(start, count); } static IEnumerable<int> RangeIterator(int start, int count) { for (int i = 0; i < count; i++) yield return start + i; }
(2).Where(): A way to filter a set, accept a predicate, and apply it to each element in the original set.
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) { if (source == null) throw ("source"); if (predicate == null) throw ("predicate"); if (source is Iterator<TSource>) return ((Iterator<TSource>)source).Where(predicate); if (source is TSource[]) return new WhereArrayIterator<TSource>((TSource[])source, predicate); if (source is List<TSource>) return new WhereListIterator<TSource>((List<TSource>)source, predicate); return new WhereEnumerableIterator<TSource>(source, predicate); } public WhereEnumerableIterator(IEnumerable<TSource> source, Func<TSource, bool> predicate) { = source; = predicate; }
The above introduces two methods: Range() and Where(), which mainly includes select(), orderby() and other methods.
Common methods in the class:
(1).IQueryable interface:
/// <summary> /// Provides the ability to calculate queries for specific data sources with unspecified data types. /// </summary> /// <filterpriority>2</filterpriority> public interface IQueryable : IEnumerable { /// <summary> /// Get the expression directory tree associated with the instance of <see cref="T:"/>. /// </summary> /// /// <returns> /// The <see cref="T:"/> associated with this instance of <see cref="T:"/>. /// </returns> Expression Expression { get; } /// <summary> /// Gets the type of element returned when executing the expression directory tree associated with this instance of <see cref="T:"/>. /// </summary> /// /// <returns> /// A <see cref="T:"/> represents the type of element returned when executing the associated expression directory tree. /// </returns> Type ElementType { get; } /// <summary> /// Get the query provider associated with this data source. /// </summary> /// /// <returns> /// The <see cref="T:"/> associated with this data source. /// </returns> IQueryProvider Provider { get; } }
(2).Where():
public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate) { if (source == null) throw ("source"); if (predicate == null) throw ("predicate"); return <TSource>( ( null, ((MethodInfo)()).MakeGenericMethod(typeof(TSource)), new Expression[] { , (predicate) } )); }
(3).Select():
public static IQueryable<TResult> Select<TSource,TResult>(this IQueryable<TSource> source, Expression<Func<TSource, TResult>> selector) { if (source == null) throw ("source"); if (selector == null) throw ("selector"); return <TResult>( ( null, ((MethodInfo)()).MakeGenericMethod(typeof(TSource), typeof(TResult)), new Expression[] { , (selector) } )); }
The above is a simple analysis of the two classes in the extension method.
4. Extension method example:
Since the extension method is actually a call to a static method, the CLR will not generate code to null value check the value of the expression that calls the method.
1.Exception handling code:
/// <summary> /// Provide useful methods for parameter verification /// </summary> public static class ArgumentValidator { /// <summary> /// If argumentToValidate is empty, an ArgumentNullException is thrown /// </summary> public static void ThrowIfNull(object argumentToValidate, string argumentName) { if (null == argumentName) { throw new ArgumentNullException("argumentName"); } if (null == argumentToValidate) { throw new ArgumentNullException(argumentName); } } /// <summary> /// If argumentToValidate is empty, an ArgumentException exception is thrown /// </summary> public static void ThrowIfNullOrEmpty(string argumentToValidate, string argumentName) { ThrowIfNull(argumentToValidate, argumentName); if (argumentToValidate == ) { throw new ArgumentException(argumentName); } } /// <summary> /// If condition is true, throw an ArgumentException exception /// </summary> /// <param name="condition"></param> /// <param name="msg"></param> public static void ThrowIfTrue(bool condition, string msg) { ThrowIfNullOrEmpty(msg, "msg"); if (condition) { throw new ArgumentException(msg); } } /// <summary> /// If the file exists in the specified directory, a FileNotFoundException will be thrown /// </summary> /// <param name="fileSytemObject"></param> /// <param name="argumentName"></param> public static void ThrowIfDoesNotExist(FileSystemInfo fileSytemObject, String argumentName) { ThrowIfNull(fileSytemObject, "fileSytemObject"); ThrowIfNullOrEmpty(argumentName, "argumentName"); if (!) { throw new FileNotFoundException("'{0}' not found".Fi()); } } public static string Fi(this string format, params object[] args) { return FormatInvariant(format, args); } /// <summary> /// Format strings and use <see cref="">unchanging culture</see>. /// </summary> /// <remarks> /// <para>This should be "B">" used when displaying any string to the user. It means log /// Messages, exception messages, and other types of information do not allow them to enter the user interface, or will not ///It makes sense to the user anyway;).</para> /// </remarks> public static string FormatInvariant(this string format, params object[] args) { ThrowIfNull(format, "format"); return 0 == ? format : (, format, args); } /// <summary> /// If the time is not, an ArgumentException exception is thrown /// </summary> /// <param name="argumentToValidate"></param> /// <param name="argumentName"></param> public static void ThrowIfNotUtc(DateTime argumentToValidate, String argumentName) { ThrowIfNullOrEmpty(argumentName, "argumentName"); if ( != ) { throw new ArgumentException("You must pass an UTC DateTime value", argumentName); } } }
2. Enumerate extension method:
public static class EnumExtensions { /// <summary> /// Get the name /// </summary> /// <param name="e"></param> /// <returns></returns> public static string GetName(this Enum e) { return ((), e); } /// <summary> /// Get the name and value /// </summary> /// <param name="enumType">Enum</param> /// <param name="lowerFirstLetter">Whether to lowercase</param> /// <returns></returns> public static Dictionary<string, int> GetNamesAndValues( this Type enumType, bool lowerFirstLetter) { // Since the extension method is actually a call to a static method, the CLR will not generate code to check the value of the expression that calls the method for null value. (enumType, "enumType"); //Get the enum name array var names = (enumType); //Get the enum value array var values = (enumType); var d = new Dictionary<string, int>(); for (var i = 0; i < ; i++) { var name = lowerFirstLetter ? names[i].LowerFirstLetter() : names[i]; d[name] = Convert.ToInt32((i)); } return d; } /// <summary> /// Convert to lowercase /// </summary> /// <param name="s"></param> /// <returns></returns> public static string LowerFirstLetter(this string s) { (s, "s"); return (s[0]) + (1); } }
5. Summary:
In this article, we mainly provide some rules, declaration methods, usage methods, and simple answers to the extension method's significance and principles of the extension method. And at the end of this article, an enum extension method code is given.
The above is the detailed content of the C# extension method summary. For more information about the C# extension method, please pay attention to my other related articles!