网站导航网学 原创论文 原创专题 网站设计 最新系统 原创论文 论文降重 发表论文 论文发表 UI设计定制 论文答辩PPT格式排版 期刊发表 论文专题
返回网学首页
网学原创论文
最新论文 推荐专题 热门论文 论文专题
当前位置: 网学 > 设计资源 > .Net编程 > 正文

扩展方法详解

论文降重修改服务、格式排版等 获取论文 论文降重及排版 论文发表 相关服务

一、基础
扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。扩展方法是一种特殊的静态方法,调用扩展方法与调用在类型中实际定义的方法之间没有明显的差异。扩展方法是可以通过使用实例方法语法调用的静态方法。效果上,使得附加的方法扩展已存在类型和构造类型成为可能。他可以对现有类功能进行扩充,从而使该类型的实例具有更多的方法。扩展方法有助于把今天动态语言中流行的对快速录入支持的灵活性,与强类型语言之性能和编译时验证融合起来。这里先举一个msdn中的例子:
下面的示例演示为 System.String 类定义的一个扩展方法。假设我要分析一个字符串,希望得到字符串中单词的个数,一般情况下我们可能使用一个统计的函数来解决这个问题

  1. static void Main(string args) 
  2.        { 
  3.            string s = "Hello Extension Methods"
  4.            Console.WriteLine(WordCount(s)); 
  5.            //Console.WriteLine(s.WordCount()); 
  6.        } 
  7.        static int WordCount(string str) 
  8.        { 
  9.            return str.Split(new char { ' ''.''?' }, StringSplitOptions.RemoveEmptyEntries).Length; 
  10.        } 

但这样用起来感觉上可能会很别扭,这个WordCount方法如果就是字符串类中的一个方法多好,像所有字符串的实例方法一样用。这里我们引出扩展方法来解决这个问题。

  1. public static class MyExtensions 
  2.     { 
  3.         public static int WordCount(this String str) 
  4.         { 
  5.             return str.Split(new char { ' ''.''?' }, StringSplitOptions.RemoveEmptyEntries).Length; 
  6.         } 
  7.     } 

注意,上面的静态方法在第一个类型是string的参数变量前有个“this”关键词,这告诉编译器,这个特定的扩展方法应该添加到类型为“string”的对象中去。
使用 using 指令将 WordCount 扩展方法放入范围中:
using ExtensionMethods;

  1. string s = "Hello Extension Methods"
  2. int i = s.WordCount(); 

二、应用场景
1、扩展类库中已经存在的类
比方说我们是无法改变系统已经存在的类的,就像上例中我们无法在string类中添加WordCount方法,但我又希望在使用时直接使用

2、多个类实现接口时有些方法实现方式相同,所以不希望每个实现类中重新实现一遍
假如系统中用户接口需要两个类实现,希望IUser接口声明的实体都有检测Email的方法IsUniqueEmail,而实际上这个方法在所有实现类中的实现逻辑都是一样的,而我们如果把这个方法添加到IUser中,那么两个类就要都实现一遍IsUniqueEmail的逻辑。中间加一层继承关系也可以解决问题,这种方式会增加维护成本,这时我们可以使用扩展方法
如下图:

代码模拟如下:

  1. interface IUser 
  2.     { 
  3.         string Email { getset; } 
  4.         string Name { getset; } 
  5.     } 
  6.     class UserLinqToOracle : IUser 
  7.     { 
  8.         #region IUser 成员 
  9.  
  10.         private string email; 
  11.         public string Email 
  12.         { 
  13.             get 
  14.             { 
  15.                 return email; 
  16.             } 
  17.             set 
  18.             { 
  19.                 email=value; 
  20.             } 
  21.         } 
  22.         private string name; 
  23.         public string Name 
  24.         { 
  25.             get 
  26.             { 
  27.                 return name; 
  28.             } 
  29.             set 
  30.             { 
  31.                 name = value; 
  32.             } 
  33.         } 
  34.  
  35.         #endregion 
  36.     } 
  37.     class UserLinqToSql : IUser 
  38.     { 
  39.         #region IUser 成员 
  40.  
  41.         private string email; 
  42.         public string Email 
  43.         { 
  44.             get 
  45.             { 
  46.                 return email; 
  47.             } 
  48.             set 
  49.             { 
  50.                 email=value; 
  51.             } 
  52.         } 
  53.         private string name; 
  54.         public string Name 
  55.         { 
  56.             get 
  57.             { 
  58.                 return name; 
  59.             } 
  60.             set 
  61.             { 
  62.                 name = value; 
  63.             } 
  64.         } 
  65.  
  66.         #endregion 
  67.     } 
  1. static class UserExtension 
  2.     { 
  3.         public static bool IsUniqueEmail(this IUser forUser, string email) 
  4.         { 
  5.             return CheckEmail(email); 
  6.         } 
  7.  
  8.         private static bool CheckEmail(string email) 
  9.         { 
  10.             return true
  11.         } 
  12.     } 
  1. static void Main(string args) 
  2.         { 
  3.             IUser user = new UserLinqToOracle(); 
  4.             Console.WriteLine(user.IsUniqueEmail("")); 
  5.         } 

三、扩展方法要点
1、扩展方法的本质为将实例方法调用在编译期改变为静态类中的静态方法调用。事实上,它确实拥有静态方法所具有的所有功能。
2、通常,您更多时候是调用扩展方法而不是实现您自己的扩展方法。由于扩展方法是使用实例方法语法调用的,因此不需要任何特殊知识即可从客户端代码中使用它们。若要为特定类型启用扩展方法,只需为在其中定义这些方法的命名空间添加 using 指令。
3、扩展方法的优先级:现有实例方法优先级最高,其次为最近的namespace下的静态类的静态方法,最后为较远的namespace下的静态类的静态方法。(与接口或类方法具有相同名称和签名的扩展方法永远不会被调用 ) 

  1. class Program 
  2.     { 
  3.         static void Main(string args) 
  4.         { 
  5.             User user = new User() { FirstName = "l", LastName = "fm" }; 
  6.             Console.WriteLine(user.FullName()); 
  7.         } 
  8.  
  9.          
  10.     } 
  11.     public class User 
  12.     { 
  13.         public string FirstName { getset; } 
  14.         public string LastName { getset; } 
  15.         public  string FullName() 
  16.         { 
  17.             return "来源于实例方法:" + FirstName + LastName; 
  18.         } 
  19.     } 
  20.     public static class MyExtensions 
  21.     { 
  22.         public static string FullName(this User user) 
  23.         { 
  24.             return "来源于扩展方法:"+user.FirstName+user.LastName; 
  25.         } 
  26.     } 

结果为“来源于实例方法:lfm”

  1. namespace ConsoleApplication7 
  2.     using MyNamespace; 
  3.     class Program 
  4.     { 
  5.         static void Main(string args) 
  6.         { 
  7.             User user = new User() { FirstName = "l", LastName = "fm" }; 
  8.             Console.WriteLine(user.FullName()); 
  9.         } 
  10.  
  11.          
  12.     } 
  13.     public class User 
  14.     { 
  15.         public string FirstName { getset; } 
  16.         public string LastName { getset; } 
  17.     } 
  18.     public static class MyExtensions 
  19.     { 
  20.         public static string FullName(this User user) 
  21.         { 
  22.             return "来源于较近的扩展方法:"+user.FirstName+user.LastName; 
  23.         } 
  24.     } 
  25. namespace MyNamespace 
  26.     using ConsoleApplication7; 
  27.     public static class MyExtensions 
  28.     { 
  29.         public static string FullName(this User user) 
  30.         { 
  31.             return "来源于较远的扩展方法:" + user.FirstName + user.LastName; 
  32.         } 
  33.     } 

结果为:“来源于较近的扩展方法:lfm”
4、在接口上扩展的方法,如果用接口声明时会优先使用基于接口的扩展方法

  1. class Program 
  2.     { 
  3.         static void Main(string args) 
  4.         { 
  5.             IUser user = new User() { FirstName = "l", LastName = "fm", Email = "lfm@126.com" }; 
  6.             Console.WriteLine(user.GetEmail()); 
  7.         } 
  8.     } 
  9.     public interface IUser 
  10.     { 
  11.         string FirstName { getset; } 
  12.         string LastName { getset; } 
  13.         string Email { getset; } 
  14.     } 
  15.     public class User : IUser 
  16.     { 
  17.         public string FirstName { getset; } 
  18.         public string LastName { getset; } 
  19.         public string Email { getset; } 
  20.         public  string GetEmail() 
  21.         { 
  22.             return "来源实例方法:" + Email; 
  23.         } 
  24.     } 
  25.     public static class MyExtensions 
  26.     { 
  27.         public static string GetEmail(this IUser forUser) 
  28.         { 
  29.             return "来源扩展方法:" + forUser.Email; 
  30.         } 
  31.     } 

结果为:来源于扩展方法:lfm@126.com
但如果接口中又被添加了相应的方法,将优先使用实例方法

  1. class Program 
  2.     { 
  3.         static void Main(string args) 
  4.         { 
  5.             IUser user = new User() { FirstName = "l", LastName = "fm", Email = "lfm@126.com" }; 
  6.             Console.WriteLine(user.GetEmail()); 
  7.         } 
  8.     } 
  9.     public interface IUser 
  10.     { 
  11.         string FirstName { getset; } 
  12.         string LastName { getset; } 
  13.         string Email { getset; } 
  14.         string GetEmail(); 
  15.     } 
  16.     public class User : IUser 
  17.     { 
  18.         public string FirstName { getset; } 
  19.         public string LastName { getset; } 
  20.         public string Email { getset; } 
  21.         public  string GetEmail() 
  22.         { 
  23.             return "来源实例方法:" + Email; 
  24.         } 
  25.     } 
  26.     public static class MyExtensions 
  27.     { 
  28.         public static string GetEmail(this IUser forUser) 
  29.         { 
  30.             return "来源扩展方法:" + forUser.Email; 
  31.         } 
  32.     } 

结果为:来源于实例方法:lfm@126.com
5、在代码中,可以使用实例方法语法调用该扩展方法。但是,编译器生成的中间语言 (IL) 会将代码转换为对静态方法的调用。因此,并未真正违反封装原则。实际上,扩展方法无法访问它们所扩展的类型中的私有变量。

四、扩展方法通用准则
1、通常,建议您只在不得已的情况下才实现扩展方法,并谨慎地实现。只要有可能,必须扩展现有类型的客户端代码都应该通过创建从现有类型派生的新类型来达到这一目的。
2、在使用扩展方法来扩展您无法更改其源代码的类型时,您需要承受该类型实现中的更改会导致扩展方法失效的风险。
3、如果您确实为给定类型实现了扩展方法,请记住以下两点:
如果扩展方法与该类型中定义的方法具有相同的签名,则扩展方法永远不会被调用。
扩展方法在命名空间级别被放入范围中。例如,如果您在同一个名为 Extensions 的命名空间中具有多个包含扩展方法的静态类,则这些扩展方法将全部由 using Extensions; 指令放入范围中。 

设为首页 | 加入收藏 | 网学首页 | 原创论文 | 计算机原创
版权所有 网学网 [Myeducs.cn] 您电脑的分辨率是 像素
Copyright 2008-2020 myeducs.Cn www.myeducs.Cn All Rights Reserved 湘ICP备09003080号 常年法律顾问:王律师