• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
我的成长足迹
夫志当存高远
博客园    首页    新随笔    联系   管理    订阅  订阅

扩展方法到底做了什么

扩展方法是.net3.5以后出现的一个比较优雅的写法,昨天讨论中有同学提出这也是通过反射实现的,不过我并不这么认为。

扩展方法的定义必须是静态类的静态方法,对一个静态类的静态方法进行反射明显不明智。而且linq to object中大量使用扩展方法,如果是用发射实现方法调用,明显过于笨拙。

那么事实到底如何

先定义一个扩展方法和一个同样功能的非扩展方法


扩展方法定义
public static class StringHelp
    {

       
/// <summary>
        
/// 裁减字符串(扩展方法写法)
        
/// </summary>
        
/// <param name="source"></param>
        
/// <param name="length"></param>
        
/// <returns></returns>
        public static string CutStr(this string source, int length, string lastString)
        {
            
if (string.IsNullOrEmpty(source))
                
return "";
            
if (source.Length > length)
            {
                
string result = string.Empty;
                source.ToCharArray().Take(length).ToList().ForEach(p 
=> { result += p.ToString(); });
                
return result + lastString;
            }
            
else
                
return source;
        }
        
/// <summary>
        
/// 裁减字符串(非扩展方法写法)
        
/// </summary>
        
/// <param name="source"></param>
        
/// <param name="length"></param>
        
/// <returns></returns>
        public static string CutStrNew(string source, int length, string lastString)
        {
            
if (string.IsNullOrEmpty(source))
                
return "";
            
if (source.Length > length)
            {
                
string result = string.Empty;
                source.ToCharArray().Take(length).ToList().ForEach(p 
=> { result += p.ToString(); });
                
return result + lastString;
            }
            
else
                
return source;
        }
    }


 

然后分别进行扩展方法调用,静态方法调用,反射调用三种调用 

 

代码调用和效率比较
class Program
    {
        
static void Main(string[] args)
        {
            
string str = "hello world!";
            Stopwatch watch 
= new Stopwatch();
            Console.WriteLine(str.CutStr(
5, "..."));
            Console.WriteLine(StringHelp.StringHelp.CutStrNew(str, 
5, "..."));
            Console.WriteLine(
typeof(StringHelp.StringHelp).GetMethod("CutStr").Invoke(null, new object[] { str, 5, "..." }));

            
//效率比较
            watch.Start();
            
for (int i = 0; i < 100000; i++)
            {
                str.CutStr(
5, "...");
            }
            watch.Stop();
            
            Console.WriteLine(
"1:"+watch.ElapsedMilliseconds);

            watch.Restart();
            
for (int i = 0; i < 100000; i++)
            {
                StringHelp.StringHelp.CutStrNew(str, 
5, "...");
            }
            watch.Stop();
            Console.WriteLine(
"2:" + watch.ElapsedMilliseconds);

            watch.Restart();
            
for (int i = 0; i < 100000; i++)
            {
                
typeof(StringHelp.StringHelp).GetMethod("CutStr").Invoke(null, new object[] { str, 5, "..." });
            }
            watch.Stop();
            Console.WriteLine(
"3:" + watch.ElapsedMilliseconds);

            Console.Read();
        }
    }


 

 

IL代码

IL代码
IL_0000:  nop
  IL_0001:  ldstr      
"hello world!"
  IL_0006:  stloc.
0
  IL_0007:  ldloc.
0
  IL_0008:  ldc.i4.
5
  IL_0009:  ldstr      
"..."
  IL_000e:  call       
string [StringHelp]StringHelp.StringHelp::CutStr(string,
                                                                        int32,
                                                                        
string)
  IL_0013:  call       
void [mscorlib]System.Console::WriteLine(string)
  IL_0018:  nop
  IL_0019:  ldloc.
0
  IL_001a:  ldc.i4.
5
  IL_001b:  ldstr      
"..."
  IL_0020:  call       
string [StringHelp]StringHelp.StringHelp::CutStrNew(string,
                                                                           int32,
                                                                           
string)
  IL_0025:  call       
void [mscorlib]System.Console::WriteLine(string)
  IL_002a:  nop
  IL_002b:  ldtoken    [StringHelp]StringHelp.StringHelp
  IL_0030:  call       
class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
  IL_0035:  ldstr      
"CutStr"
  IL_003a:  call       instance 
class [mscorlib]System.Reflection.MethodInfo [mscorlib]System.Type::GetMethod(string)
  IL_003f:  ldnull
  IL_0040:  ldc.i4.
3
  IL_0041:  newarr     [mscorlib]System.Object
  IL_0046:  stloc.
1
  IL_0047:  ldloc.
1
  IL_0048:  ldc.i4.
0
  IL_0049:  ldloc.
0
  IL_004a:  stelem.
ref
  IL_004b:  ldloc.
1
  IL_004c:  ldc.i4.
1
  IL_004d:  ldc.i4.
5
  IL_004e:  box        [mscorlib]System.Int32
  IL_0053:  stelem.
ref
  IL_0054:  ldloc.
1
  IL_0055:  ldc.i4.
2
  IL_0056:  ldstr      
"..."
  IL_005b:  stelem.
ref
  IL_005c:  ldloc.
1
  IL_005d:  callvirt   instance 
object [mscorlib]System.Reflection.MethodBase::Invoke(object,
                                                                                      
object[])
  IL_0062:  call       
void [mscorlib]System.Console::WriteLine(object)

 



三种调用的方式是这样的:

1、string [StringHelp]StringHelp.StringHelp::CutStr(string,                                                                        int32,                                                                        string)

2、string [StringHelp]StringHelp.StringHelp::CutStrNew(string,
                                                                           int32,
                                                                           string)

3、instance object [mscorlib]System.Reflection.MethodBase::Invoke(object,
                                                                                      object[])


 

 

很明显,并没有使用反射,而是编译器的语法糖,使得调用方法更为简便。在编译时期,编译器会对代码作用域范围内可见的所有静态类,且带this 特征参数的方法进行搜索,

然后透明调用符合特征的方法。

 

那么效率如何呢

 

 


 1、86  2、84  3、313

 效率基本没有,差别,因为其实调用的方式都没有什么区别,而且性能比反射自然要好很多。

 


 

posted @ 2010-05-26 18:41  bwbwbw1984  阅读(388)  评论(5)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3