Extension method parsing for C #

Source: Internet
Author: User
In the process of using object-oriented language for project development, more use of the "inheritance" feature, but not all scenarios are appropriate to use the "inheritance" feature, in some of the basic principles of design patterns are also mentioned.





Inherited questions about the use of attributes: An object's inheritance is defined at compile time, so an implementation inherited from the parent class cannot be changed at run time. The implementation of the subclass has a very close dependency on its parent class, so that any changes in the parent class implementation will inevitably cause the subclass to change.



When you need to reuse a subclass, if the inherited implementation is not appropriate to solve the new problem, the parent must override it or be replaced by another more appropriate class, which limits flexibility and ultimately limits reusability. Instead of inheriting attributes, more of them will use the synthetic/aggregation reuse principle, the synthetic/aggregation reuse principle: Use composition/aggregation as much as possible, and do not use class inheritance as much as possible.



If an object in the new type should carry details about the extra behavior, it may sometimes be inappropriate when using the inheritance attribute, for example, when dealing with a reference type, a sealed class, or an interface. In the face of these requirements, we sometimes write static classes that contain some static methods. However, excessive static methods can cause additional unnecessary overhead.



I. Overview of extension methods:



In the face of these "inheritance" issues, and in the face of some of the project's needs, the way we need to solve these problems is the "extension method." The "extension method" is introduced in c#3.0, which has the advantages of static methods, and the readability of the code that calls them has been improved. When you use an extension method, you can call a static method just as you would call an instance method.



1. Basic principles of extension methods:



(1). C # supports only extension methods and does not support extended attributes, extended events, extension operators, and so on.



(2). The extension method (the method before the first parameter is this) must be declared in a non-generic static class, the extension method must have one parameter, and only the first parameter uses the this tag.



(3). When the C # compiler looks for extension methods in static classes, it requires that the static classes themselves have a file scope.



(4). C # compilation requires an "import" extension method. (Static methods can be arbitrarily named, and the C # compiler takes time to look up when looking for methods, needs to examine all static classes in the file scope, and scans all of their static methods to find a match)



(5). Multiple static classes can define the same extension method.



(6). When you extend a type with an extension method, the derived type is also extended.



2. Extension method declaration:



(1). Must be in a non-nested, non-generic type static class (so it must be a static method)



(2). There is at least one parameter.



(3). The first parameter must be prefixed with the 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.



The above two classification descriptions, the basic characteristics of the extension method and the way to do a simple introduction, the use of extension methods, will be shown in the following code sample, again no more instructions.



Two. Extension method principle Analysis:



The extension method is a unique method of C # that uses the ExtensionAttribute attribute in the extension method.



C # Once the first parameter of a static method is marked with the This keyword, the compiler internally applies a custom attribute to the method, which is persisted in the metadata of the resulting file, which is stored in System.core DLL assemblies.



Any static class that contains at least one extension method also applies the attribute in its metadata, and any assembly contains at least one static class that conforms to the above characteristics, and its metadata will also apply the attribute. If the code is using a nonexistent instance method, the compiler can quickly scan all referenced assemblies, determine which ones contain extension methods, and then, in this assembly, scan the static classes that contain the 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 with a simple name of type (without naming the control prefix), you can import all the namespaces in that type, but in doing so, 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 use of extension methods is for LINQ services, which provide an auxiliary extension method, located in the enumerable and Queryable classes under the System.Linq namespace. Enumerable most extensions are ienumerable<t>,queryable large majority of the extensions are iqueryable<t>.



Common methods in the 1.Enumerable class



(1). Range (): One parameter is the start number, and one is the number of results to generate.

public static IEnumerable <int> Range (int start, int count) {
            long max = ((long) start) + count-1;
            if (count <0 || max> Int32.MaxValue) throw Error.ArgumentOutOfRange ("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 the collection, accept a predicate and apply it to each element in the original collection.

public static IEnumerable <TSource> Where <TSource> (this IEnumerable <TSource> source, Func <TSource, bool> predicate) {
            if (source == null) throw Error.ArgumentNull ("source");
            if (predicate == null) throw Error.ArgumentNull ("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) {
                this.source = source;
                this.predicate = predicate;
}


The two methods of Range () and Where () are introduced above. The class also mainly includes select (), orderby () and other methods.



2. Common methods in the Queryable class:



(1) .IQueryable interface:



/// <summary>
  /// Provides the function of calculating the query of a specific data source without specifying a data type.
  /// </ summary>
  /// <filterpriority> 2 </ filterpriority>
  public interface IQueryable: IEnumerable
  {
    /// <summary>
    /// Get the expression tree associated with an instance of <see cref = "T: System.Linq.IQueryable" />.
    /// </ summary>
    ///
    /// <returns>
    /// <see cref = "T: System.Linq.Expressions.Expression" /> associated with this instance of <see cref = "T: System.Linq.IQueryable" />.
    /// </ returns>
    Expression Expression {get;}
    /// <summary>
    /// Get the type of elements returned when executing the expression tree associated with this instance of <see cref = "T: System.Linq.IQueryable" />
    /// </ summary>
    ///
    /// <returns>
    /// A <see cref = "T: System.Type" />, indicating the type of element returned when executing the expression tree associated with it.
    /// </ returns>
    Type ElementType {get;}
    /// <summary>
    /// Get the query provider associated with this data source.
    /// </ summary>
    ///
    /// <returns>
    /// <see cref = "T: System.Linq.IQueryProvider" /> 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 Error.ArgumentNull ("source");
            if (predicate == null)
                throw Error.ArgumentNull ("predicate");
            return source.Provider.CreateQuery <TSource> (
                Expression.Call (
                    null,
                    ((MethodInfo) MethodBase.GetCurrentMethod ()). MakeGenericMethod (typeof (TSource)),
                    new Expression [] {source.Expression, Expression.Quote (predicate)}
                    ));
        }




(3) .Select ():

public static IQueryable <TResult> Select <TSource, TResult> (this IQueryable <TSource> source, Expression <Func <TSource, TResult >> selector) {
            if (source == null)
                throw Error.ArgumentNull ("source");
            if (selector == null)
                throw Error.ArgumentNull ("selector");
            return source.Provider.CreateQuery <TResult> (
                Expression.Call (
                    null,
                    ((MethodInfo) MethodBase.GetCurrentMethod ()). MakeGenericMethod (typeof (TSource), typeof (TResult)),
                    new Expression [] {source.Expression, Expression.Quote (selector)}
                    ));
}


The above is a simple analysis of the two classes in the extension method.



4. Examples of extension methods:



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 of the calling method for null value



1. Exception handling code:



  /// <summary>
    /// Provide a useful method 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 is thrown
        /// </ summary>
        public static void ThrowIfNullOrEmpty (string argumentToValidate, string argumentName)
        {
            ThrowIfNull (argumentToValidate, argumentName);
            if (argumentToValidate == string.Empty)
            {
                throw new ArgumentException (argumentName);
            }
        }
        /// <summary>
        /// If condition is true, an ArgumentException is thrown
        /// </ 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>
        /// FileNotFoundException is thrown if the file exists in the specified directory
        /// </ summary>
        /// <param name = "fileSytemObject"> </ param>
        /// <param name = "argumentName"> </ param>
        public static void ThrowIfDoesNotExist (FileSystemInfo fileSytemObject, String argumentName)
        {
            ThrowIfNull (fileSytemObject, "fileSytemObject");
            ThrowIfNullOrEmpty (argumentName, "argumentName");
            if (! fileSytemObject.Exists)
            {
                throw new FileNotFoundException ("'{0}' not found" .Fi (fileSytemObject.FullName));
            }
        }
        public static string Fi (this string format, params object [] args)
        {
            return FormatInvariant (format, args);
        }
        /// <summary>
        /// Format strings and use <see cref = "CultureInfo.InvariantCulture"> unchanged culture </ see>.
        /// </ summary>
        /// <remarks>
        /// <para> This should be "B"> "B"> "" used for any string displayed to the user. It means log
        /// Messages, exception messages, and other types of information do not allow it to enter the user interface, or will not
        /// In any case, it makes sense to users;). </ Para>
        /// </ remarks>
        public static string FormatInvariant (this string format, params object [] args)
        {
            ThrowIfNull (format, "format");
            return 0 == args.Length? format: string.Format (CultureInfo.InvariantCulture, format, args);
        }
        /// <summary>
        /// If the time is not DateTimeKind.Utc, an ArgumentException is thrown
        /// </ summary>
        /// <param name = "argumentToValidate"> </ param>
        /// <param name = "argumentName"> </ param>
        public static void ThrowIfNotUtc (DateTime argumentToValidate, String argumentName)
        {
            ThrowIfNullOrEmpty (argumentName, "argumentName");
            if (argumentToValidate.Kind! = DateTimeKind.Utc)
            {
                throw new ArgumentException ("You must pass an UTC DateTime value", argumentName);
            }
        }
}


2. Enumeration 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 Enum.GetName (e.GetType (), e);
        }
        /// <summary>
        /// Get name and value
        /// </ summary>
        /// <param name = "enumType"> enumeration </ param>
        /// <param name = "lowerFirstLetter"> Whether to convert to lower case </ 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 of the calling method for null value
            ArgumentValidator.ThrowIfNull (enumType, "enumType");
            // Get an array of enumeration names
            var names = Enum.GetNames (enumType);
            // Get an array of enumeration values
            var values = Enum.GetValues (enumType);
            var d = new Dictionary <string, int> (names.Length);
            for (var i = 0; i <names.Length; i ++)
            {
                var name = lowerFirstLetter? names [i] .LowerFirstLetter (): names [i];
                d [name] = Convert.ToInt32 (values.GetValue (i));
            }
            return d;
        }
        /// <summary>
        /// Convert to lower case
        /// </ summary>
        /// <param name = "s"> </ param>
        /// <returns> </ returns>
        public static string LowerFirstLetter (this string s)
        {
            ArgumentValidator.ThrowIfNull (s, "s");
            return char.ToLowerInvariant (s [0]) + s.Substring (1);
        }
    }
5. Summary:

In this article, we mainly carried out some rule descriptions, declaration methods, usage methods, and a simple answer to the meaning and principle of the extension method. And at the end of this article, an enumerated extension method code is given.

The above is the content parsed by C # 's extension method. For more related content, please pay attention to topic.alibabacloud.com (www.php.cn)!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.