• C#中为特定类型增加扩展方法


      代码越写越多,但是我们也需要经常去反思那些写过的代码,Utility Class就是这一类需要特别去反思总结的类,这些类像工具一样,我们经常通过一些静态方法,通过传入一些参数,然后得到我们需要的结果,在下面的一系列博客中,我们就一点一滴去反思这些类,并提供一个很好的方式去为他人提供方便,促进彼此之间的相互学习。  

      首先第一个介绍的就是ParseUtil这个静态类,在我们的代码中,我们经常需要去将string类型的字符串去做一个类型转换,比如说int,double,demical,float,DateTime、short、long甚至是byte数组类型,当我们转换失败时还可以提供一个默认值,这些值能够保证一定去返回这些正确的类型值。

      这组代码的核心部分就是:  

    private static T ParseStringToType<T>(this string input, Func<string, T> action, T defaultvalue) where T : struct
            {
                if (string.IsNullOrEmpty(input))
                {
                    return defaultvalue;
                }
                try
                {
                    return action(input);
                }
                catch
                {
                    return defaultvalue;
                }
            }

      这段代码的核心部分就是通过传入一个Func<string, T>类型的委托去构建代码和算法的重用,这里涉及到一些重要的思想,一个是代码重用思想,另外就是体会到使用泛型参数T来真正地实现算法的重用机制,另外通过这个我们也可以横向比较Action、Func类型的委托以及匿名委托delegate的一些区别。

     public static class ParseUtil
        {
            public static DateTime ParseByDefault(this string input, DateTime defaultvalue)
            {
                return input.ParseStringToType<DateTime>(delegate(string e)
                {
                    return Convert.ToDateTime(input);
                }, defaultvalue);
            }
    
            public static decimal ParseByDefault(this string input, decimal defaultvalue)
            {
                return input.ParseStringToType<decimal>(delegate(string e)
                {
                    return Convert.ToDecimal(input);
                }, defaultvalue);
            }
    
            public static double ParseByDefault(this string input, double defaultvalue)
            {
                return input.ParseStringToType<double>(delegate(string e)
                {
                    return Convert.ToDouble(input);
                }, defaultvalue);
            }
    
            public static int ParseByDefault(this string input, int defaultvalue)
            {
                return input.ParseStringToType<int>(delegate(string e)
                {
                    return Convert.ToInt32(input);
                }, defaultvalue);
            }
    
            public static long ParseByDefault(this string input, long defaultvalue)
            {
                return input.ParseStringToType<long>(delegate(string e)
                {
                    return Convert.ToInt64(input);
                }, defaultvalue);
            }
    
            public static float ParseByDefault(this string input, float defaultvalue)
            {
                return input.ParseStringToType<float>(delegate(string e)
                {
                    return Convert.ToSingle(input);
                }, defaultvalue);
            }
    
            public static float ParseByDefault(this string input, short defaultvalue)
            {
                return input.ParseStringToType<short>(delegate(string e)
                {
                    return Convert.ToInt16(input);
                }, defaultvalue);
            }
    
            public static string ParseByDefault(this string input, string defaultvalue)
            {
                if (string.IsNullOrEmpty(input))
                {
                    return defaultvalue;
                }
                return input;
            }
    
            private static T ParseStringToType<T>(this string input, Func<string, T> action, T defaultvalue) where T : struct
            {
                if (string.IsNullOrEmpty(input))
                {
                    return defaultvalue;
                }
                try
                {
                    return action(input);
                }
                catch
                {
                    return defaultvalue;
                }
            }
        }
    

      另外在传入参数input之前为什么还需要传递this?这个该如何去准确理解呢?

      这就涉及到C# this扩展方法的内容了......

      扩展方法被定义为静态方法,但它们是通过实例方法语法进行调用的。 它们的第一个参数指定该方法作用于哪个类型,并且该参数以 this 修饰符为前缀。 扩展方法当然不能破坏面向对象封装的概念,所以只能是访问所扩展类的public成员。     

      扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用,C#扩展方法第一个参数指定该方法作用于哪个类型,并且该参数以 this 修饰符为前缀。

      就像上面的方法中,input是一个string类型的对象,但是 ParseStringToType这个方法是我们自己定义的一个静态方法,String类中是不存在该方法的,是我们人为去扩展的一个方法,下面举出一个相同的例子:  

    	//必须是静态类才可以添加扩展方法
           Static class Program
           {
              static void Main(string[] args)
              {
                string str = "quzijing";
                //注意调用扩展方法,必须用对象来调用 
                string Newstr = str.Add();
                Console.WriteLine(Newstr);
                Console.ReadKey();
              }
            //声明扩展方法
            //扩展方法必须是静态的,Add有三个参数
            //this 必须有,string表示我要扩展的类型,stringName表示对象名
            //三个参数this和扩展的类型必不可少,对象名可以自己随意取如果需要传递参数,//再增加一个变量即可
    
              public static  string  Add(this string stringName)
              {
                return stringName+"a";
              }
          }		
    

      既然string类可以通过这种方式来扩展方法,那么我们定义的一般类呢?答案也是可以的。  

      给自定义的类型增加一个扩展方法,并增加一个传递的参数

      (1)、声明一个Student类,它包含了两个方法StuInfo,getStuInfo

     public class Student
        {
            public string StuInfo()
            {
                return "学生基本信息";
            }
            public  string getStuInfo(string stuName, string stuNum)
            {
           return string.Format("学生信息:\n" + "姓名:{0} \n" + "学号:{1}",      stuName, stuNum);
            }
         } 
    

      (2)、声明一个名为ExtensionStudentInfo的静态类,注意必须为静态

      这个类的作用就是包含一些我们想要扩展的方法,在此我们声明两个Student类型的扩展方法,Student类型为我们自定义的类型。

    public static class ExtensionStudentInfo
        {
            //声明扩展方法
            //要扩展的方法必须是静态的方法,Add有三个参数
            //this 必须有,string表示我要扩展的类型,stringName表示对象名
            //三个参数this和扩展的类型必不可少,对象名可以自己随意取如果需要传递参数,再增加一个变量即可
            public static string ExtensionStuInfo(this Student stuName)
            {
                return stuName.StuInfo();
            }
            //声明扩展方法
            //要扩展的方法必须是静态的方法,Add有三个参数
            //this 必须有,string表示我要扩展的类型,stringName表示对象名
            //三个参数this和扩展的类型必不可少,对象名可以自己随意取如果需要传递参数,在此我们增加了两个string类型的参数
            public static string ExtensionGetStuInfo(this Student student, string stuname, string stunum)
            {
                return student.getStuInfo(stuname, stunum)+"\n读取完毕";
            }
        }
    

        下面来建一个测试的应用程序来看看输出的结果

     static void Main(string[] args)
            {
                Student newstudent = new Student();
                //要使用对象调用我们的扩展方法
                string stuinfo = newstudent.ExtensionStuInfo();
                Console.WriteLine(stuinfo);
                //要使用对象调用我们的扩展方法
                string stuinformation = newstudent.ExtensionGetStuInfo("张三", "001");
                Console.WriteLine(stuinformation);
                Console.ReadKey();
            }
    

      获取的结果是:

    最后借用网上的一个例子来结束这一内容的介绍。
    		
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions; 
    //声明扩展方法的步骤:类必须是static,方法是static,
    //第一个参数是被扩展的对象,前面标注this。
    //使用扩展方法的时候必须保证扩展方法类已经在当前代码中using
    namespace 扩展方法
    {
    
        //扩展方法必须是静态的
        public static class StringHelper
        {
            //扩展方法必须是静态的,第一个参数必须加上this
            public static bool IsEmail(this string _input)
            {
                return Regex.IsMatch(_input, @"^\w+@\w+\.\w+$");
            }
    
            //带多个参数的扩展方法
            //在原始字符串前后加上指定的字符
            public static string Quot(this string _input, string _quot)
            {
                return _quot + _input + _quot;
            }
    
        }
    
    }	
    

      通过扩展类,我们可以为string类扩展一些原先不太需要的方法来完成我们的需求。

    			
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    namespace 扩展方法
    {
        class Program
        {
            static void Main(string[] args)
            {
                string _myEmail = "abc@163.com";
                //这里就可以直接使用string类的扩展方法IsEmail了
                Console.WriteLine(_myEmail.IsEmail());
                //调用接收参数的扩展方法
                Console.WriteLine(_myEmail.Quot("!"));
                Console.ReadLine();
            }
    
        }
    
    }		
    

      就像我们的ParseUtil类定义的那样,我们可以通过定义string str,然后通过str.ParseByDefault(0D)直接将我们将string直接转化为double类型,而不用在每个地方都重复去写代码,这些都需要我们不断去反思总结代码,代码才能越写越好;

     
  • 相关阅读:
    测试人生 | 40+的年龄50W+的年薪,2线城市入职名企,他曾想放弃测试?
    干货 | 面试过了,如何谈薪资?拿高薪Offer有哪些技巧?
    测试人生 | 三十而立终圆大厂梦,测试开发开启新征程
    测试人生 | 97年双非学历的小哥哥,2线城市涨薪100%,我酸了......
    一道有趣的大厂测试面试题,你能用 Python or Shell 解答吗?
    一道大厂测试开发面试真题,你需要几分钟解答?
    测试人生 | 专科学历入职世界500强企业,二线城市年薪超30W,这个80后小哥哥很赞!
    测试人生 | 00后拿下了名企大厂 offer,这个后浪学习之路全公开
    测试人生 | 三十而已,何需惧怕!年薪40W+涨薪幅度超40%
    使用 Serverless Devs 插件快速部署前端应用
  • 原文地址:https://www.cnblogs.com/seekdream/p/6035428.html
Copyright © 2020-2023  润新知