zoukankan      html  css  js  c++  java
  • 扩展方法到底做了什么

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

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


  • 相关阅读:
    372. Super Pow
    桌面远程连接:发生身份验证错误,要求的函数不受支持
    Web Service代理类生成工具
    Razor语法大全
    Web Serveice服务代理类生成及编译
    配置WCF Test Client
    我与春风皆过客,你携秋水揽星河
    机器学习(十三) 集成学习和随机森林(下)
    机器学习(十三) 集成学习和随机森林(上)
    机器学习(十二) 决策树(下)
  • 原文地址:https://www.cnblogs.com/brightwang/p/1744672.html
Copyright © 2011-2022 走看看