扩展方法到底做了什么

扩展方法是.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

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

 


 

你可能感兴趣的:(方法)