继续的有关特征的运用所带来的题目:对象的继续关联着实编译时就定义好了,所以没法在运行时转变从父类继续的完成。子类的完成与它父类有非常严密的依靠关联,以至于父类完成中的任何变化必然会致使子类发生变化。
当你须要复用子类时,假如继续下来的完成不合适处置惩罚新的题目,则父类必需重写它或被其他更合适的类替换,这类依靠关联限定了灵活性并终究限定了复用性。替换继续特征的体式格局,较多的会采纳 合成/聚合复用准绳,“合成/聚合复用准绳”:只管运用合成/聚合,只管不要运用类继续。
假如在新范例的对象应该照顾有关分外行动的细节,在运用继续特征时,偶然能够不太合适,比方:处置惩罚指范例,密封类,或许接口时。在面临这些请求时,我们偶然候会写一些静态类包括一些静态要领。然则过量的静态要领会形成分外的不必要的开支。
一.扩大要领概述:
面临以上的有关“继续”的题目,以及在面临项目的一些需求时,我们须要处置惩罚这些题目的体式格局就是“扩大要领”。在C#3.0中引入了“扩大要领”,既有静态要领的长处,又使挪用它们的代码的可读性得到了进步。在运用扩大要领时,能够像挪用实例要领那样挪用静态要领。
1.扩大要领的基础准绳:
(1).C#只支撑扩大要领,不支撑扩大属性、扩大事宜、扩大操作符等。
(2).扩大要领(第一个参数前面是this的要领)必需在非泛型的静态类中声明,扩大要领必需有一个参数,而且只需第一个参数运用this标记。
(3).C#编译器查找静态类中的扩大要领时,请求这些静态类自身必需具有文件作用域。
(4).C#编译请求“导入”扩大要领。(静态要领能够恣意定名,C#编译器在寻觅要领时,须要消费时刻举行查找,须要搜检文件作用域中的一切的静态类,并扫描它们的一切静态要领来查找一个婚配)
(5).多个静态类能够定义雷同的扩大要领。
(6).用一个扩大要领扩大一个范例时,同时也扩大了派生范例。
2.扩大要领声明:
(1).必需在一个非嵌套的、非泛型型的静态类中(所以必需是一个静态要领)
(2).最少有一个参数。
(3).第一个参数必需附加this关键字做前缀。
(4).第一个参数不能有其他任何修饰符(如ref或out)。
(5).第一个参数的范例不能是指针范例。
以上的两个分类申明中,对扩大要领的基础特征和声明体式格局做了一个简朴的引见,有关扩大要领的运用体式格局,会在背面的代码样例中举行展现,再次就不再多做申明。
二.扩大要领道理剖析:
“扩大要领”是C#独占的一种要领,在扩大要领中会运用ExtensionAttribute这个attribute。
C#一旦运用this关键字标记了某个静态要领的第一个参数,编译器就会在内部向该要领运用一个定制的attribute,这个attribute会在终究生成的文件的元数据中持久性的存储下来,此属性在System.Core dll顺序鸠合。
任何静态类只需包括了最少一个扩大要领,它的元数据中也会运用这个attribute,任何一个顺序集包括了最少一个相符上述特性的静态类,它的元数据也会运用这个attribute。假如代码嗲用了一个不存在的实例要领,编译器会疾速的扫描援用的一切顺序集,推断它们哪些包括了扩大要领,然后,在这个顺序鸠合,能够扫描包括了扩大要领的静态类。
假如同一个定名空间中的两个类含有扩大范例雷同的要领,就没有办法做到只用个中一个类中的扩大要领。为了经由过程范例的简朴称号(没有定名控件前缀)来运用范例,能够导入该范例一切在的定名空间,但如许做的时刻,你没有办法阻挠谁人定名空间中的扩大要领也被导入进来。
三..NET3.5的扩大要领Enumerable和Queryable:
在框架中,扩大要领最大的用处就是为LINQ效劳,框架供应了辅佐的扩大要领,位于System.Linq定名空间下的Enumerable和Queryable类。Enumerable大多半扩大是IEnumerable<T>,Queryable大大多半扩大是IQueryable<T>。
1.Enumerable类中的经常使用要领
(1).Range():一个参数是肇端数,一个是要生成的效果数。
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():对鸠合举行过滤的一个体式格局,接收一个谓词,并将其运用于原始鸠合中的每一个元素。
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; }
以上离别引见了Range()和Where()两个要领,该类中还重要包括select()、orderby()等等要领。
2.Queryable类中的经常使用要领:
(1).IQueryable接口:
/// <summary> /// 供应对未指定数据范例的特定数据源的查询举行盘算的功用。 /// </summary> /// <filterpriority>2</filterpriority> public interface IQueryable : IEnumerable { /// <summary> /// 猎取与 <see cref="T:System.Linq.IQueryable"/> 的实例关联的表达式目次树。 /// </summary> /// /// <returns> /// 与 <see cref="T:System.Linq.IQueryable"/> 的此实例关联的 <see cref="T:System.Linq.Expressions.Expression"/>。 /// </returns> Expression Expression { get; } /// <summary> /// 猎取在实行与 <see cref="T:System.Linq.IQueryable"/> 的此实例关联的表达式目次树时返回的元素的范例。 /// </summary> /// /// <returns> /// 一个 <see cref="T:System.Type"/>,示意在实行与之关联的表达式目次树时返回的元素的范例。 /// </returns> Type ElementType { get; } /// <summary> /// 猎取与此数据源关联的查询供应顺序。 /// </summary> /// /// <returns> /// 与此数据源关联的 <see cref="T:System.Linq.IQueryProvider"/>。 /// </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) } )); }
以上是对扩大要领中两个类举行了一个简朴的剖析。
四.扩大要领实例:
因为扩大要领现实是对一个静态要领的挪用,所以CLR不会生成代码对挪用要领的表达式的值举行null值搜检
1.非常处置惩罚代码:
/// <summary> /// 为参数考证供应有效的要领 /// </summary> public static class ArgumentValidator { /// <summary> /// 假如argumentToValidate为空,则抛出一个ArgumentNullException非常 /// </summary> public static void ThrowIfNull(object argumentToValidate, string argumentName) { if (null == argumentName) { throw new ArgumentNullException("argumentName"); } if (null == argumentToValidate) { throw new ArgumentNullException(argumentName); } } /// <summary> /// 假如argumentToValidate为空,则抛出一个ArgumentException非常 /// </summary> public static void ThrowIfNullOrEmpty(string argumentToValidate, string argumentName) { ThrowIfNull(argumentToValidate, argumentName); if (argumentToValidate == string.Empty) { throw new ArgumentException(argumentName); } } /// <summary> /// 假如condition为真,则抛出ArgumentException非常 /// </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非常 /// </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> /// 格式化字符串和运用<see cref="CultureInfo.InvariantCulture">稳定的文明</see>. /// </summary> /// <remarks> /// <para>这应该是用于显现给用户的任何字符串时运用的“B”>“B”>“”。它意味着日记 ///音讯,非常音讯,和其他范例的信息,不使其进入用户界面,或不会 ///无论如何,对用户都有意义;).</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> /// 假如时刻不为DateTimeKind.Utc,则抛出ArgumentException非常 /// </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.罗列扩大要领:
public static class EnumExtensions { /// <summary> /// 猎取名字 /// </summary> /// <param name="e"></param> /// <returns></returns> public static string GetName(this Enum e) { return Enum.GetName(e.GetType(), e); } /// <summary> /// 猎取名字和值 /// </summary> /// <param name="enumType">罗列</param> /// <param name="lowerFirstLetter">是不是转化为小写</param> /// <returns></returns> public static Dictionary<string, int> GetNamesAndValues( this Type enumType, bool lowerFirstLetter) { //因为扩大要领现实是对一个静态要领的挪用,所以CLR不会生成代码对挪用要领的表达式的值举行null值搜检 ArgumentValidator.ThrowIfNull(enumType, "enumType"); //猎取罗列称号数组 var names = Enum.GetNames(enumType); //猎取罗列值数组 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> /// 转换为小写 /// </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); } }
五.总结:
在本文中,重要对扩大要领举行了一些划定规矩申明、声明体式格局,运用体式格局,以及对扩大要领的意义和扩大要领的道理举行了简朴的解答。并在本文的末了给了一个罗列的扩大要领代码。
以上就是C#的扩大要领剖析的内容,更多相关内容请关注ki4网(www.ki4.cn)!