zoukankan      html  css  js  c++  java
  • .NET开发中经常用到的扩展方法

    .NET开发中经常用到的扩展方法

     

    整理一下自己经常用到的几个扩展方法,在实际项目中确实好用,节省了不少的工作量。

    1  匿名对象转化

    在WinForm中,如果涉及较长时间的操作,我们一般会用一个BackgroundWorker来做封装长时间的操作,给它传递一个类型参数。

    var parm = new { UserId = txtUserId.Text, UserText = txtText.Text, TabIndex = tabControl.SelectedIndex, CheckUrl = urls, 
    SupportFormat = supportFormat, DeleteMHT = chkDelete.Checked, FileFormat=supportFileFormat };
    backgroundWorker.RunWorkerAsync(parm);
     

    注意到一点,我这里没有用一个类型,而是用一个匿名类型,以节省类型的定义。这种场景经常遇到,比如这个后台方法需要传三个参数,那个后台方法需要五个参数,如果不用我这个方法,那你需要额外的定义二个类型,分别包含三个参数或是五个参数。

    再来看DoWork时,如何使用这个匿名方法

    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
                #region Download 
         backgroundWorker.ReportProgress(10, string.Format("Analyst beginning......"));
         var parm = e.Argument.TolerantCast(new { UserId = string.Empty, UserText = string.Empty, TabIndex = 0, 
    CheckUrl = new List<string>(), SupportFormat = string.Empty, DeleteMHT = false, FileFormat=string.Empty});
    

    与RunWorkerAsnyc中传递的参数一样,定义一个匿名类型,各属性放默认值,然后调用TolerantCast方法,即可得到前面传入的值。

    这个方法很大的方便了这种使用情景:方法与方法之间需要传递不固定的参数,但是又不愿意重新定义一个新的类型。这个方法不来自于CodeProject,我把它的代码转在下面,供您参考

    /// <summary>
    /// 转换匿名类型
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="o"></param>
    /// <param name="example"></param>
    /// <returns></returns>
    public static T TolerantCast<T>(this object o, T example)
                where T : class
            {
                IComparer<string> comparer = StringComparer.CurrentCultureIgnoreCase;
                //Get constructor with lowest number of parameters and its parameters
                var constructor = typeof (T).GetConstructors(
                    BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
                    ).OrderBy(c => c.GetParameters().Length).First();
                var parameters = constructor.GetParameters();
    
                //Get properties of input object
                var sourceProperties = new List<PropertyInfo>(o.GetType().GetProperties());
    
                if (parameters.Length > 0)
                {
                    var values = new object[parameters.Length];
                    for (int i = 0; i < values.Length; i++)
                    {
                        Type t = parameters[i].ParameterType;
                        //See if the current parameter is found as a property in the input object
                        var source = sourceProperties.Find(delegate(PropertyInfo item)
                            {
                                return comparer.Compare(item.Name, parameters[i].Name) == 0;
                            });
    
                        //See if the property is found, is readable, and is not indexed
                        if (source != null && source.CanRead &&
                            source.GetIndexParameters().Length == 0)
                        {
                            //See if the types match.
                            if (source.PropertyType == t)
                            {
                                //Get the value from the property in the input object and save it for use
                                //in the constructor call.
                                values[i] = source.GetValue(o, null);
                                continue;
                            }
                            else
                            {
                                //See if the property value from the input object can be converted to
                                //the parameter type
                                try
                                {
                                    values[i] = Convert.ChangeType(source.GetValue(o, null), t);
                                    continue;
                                }
                                catch
                                {
                                    //Impossible. Forget it then.
                                }
                            }
                        }
                        //If something went wrong (i.e. property not found, or property isn't
                        //converted/copied), get a default value.
                        values[i] = t.IsValueType ? Activator.CreateInstance(t) : null;
                    }
                    //Call the constructor with the collected values and return it.
                    return (T) constructor.Invoke(values);
                }
                //Call the constructor without parameters and return the it.
                return (T) constructor.Invoke(null);
            }
     
     

     

    2 集合对象上的扩展方法

    先看例子,下面的测试方法

    var @enum = new[] {1, 2, 3, 4}.AsEnumerable();
    var sum = 0;
    @enum.ForEach(n => sum += n);
    

    这个扩展方法,可以直接在一个集合上执行一个Lambda表达式,返回结果,相当于有二个参数的Fun<T,T>,来看它的源代码定义

    public static void ForEach<T>(this IEnumerable<T> @enum, Action<T> mapFunction)
    {
          foreach (var item in @enum) mapFunction(item);
    }

     

    3 字符串类型上的扩展方法

    这里可以做的扩展方法比较多,一个明显的例子就是,依据String类型写的Helper类型方法最多。

    来看一个字符串拼凑的例子,平时我们用string.Format这样的写法,如果用下面的扩展方法,看起来更直观一些。

    string s = "{0} ought to be enough for {1}.";
    string param0 = "64K";
    string param1 = "everybody";
    
    string expected = "64K ought to be enough for everybody.";
    Assert.AreEqual(expected, s.FormatWith(param0, param1),

    这个扩展方法的定义也简单,只有一行代码

    /// <summary>
    /// Formats a string with two literal placeholders.
    /// </summary>
    /// <param name="text">The extension text</param>
    /// <param name="arg0">Argument 0</param>
    /// <param name="arg1">Argument 1</param>
    /// <returns>The formatted string</returns>
    public static string FormatWith(this string text, object arg0, object arg1)
    {
             return string.Format(text, arg0, arg1);
    }
     

    可以考虑把参数延长到任意个,改写这个扩展方法,也只需要一行代码皆可

    /// <summary>
    /// Formats a string with two literal placeholders.
    /// </summary>
    /// <param name="text">The extension text</param>
    /// <param name="arg0">Argument 0</param>
    /// <param name="arg1">Argument 1</param>
    /// <returns>The formatted string</returns>
    public static string FormatWith(this string text, params object[] args))
    {
             return string.Format(text, args);
    }

     

    另一个有用的扩展方法是字符串与枚举类型之间的转化,扩展方法定义如下

    /// <summary>
    /// Parses a string into an Enum
    /// </summary>
    /// <typeparam name="T">The type of the Enum</typeparam>
    /// <param name="value">String value to parse</param>
    /// <returns>The Enum corresponding to the stringExtensions</returns>
    public static T ToEnum<T>(this string value)
    {
                return ToEnum<T>(value, false);
     }

    参考下面的例子,使用这个实用的扩展方法

    enum ProductVersion
    {
        Standard,
        Enteprise,
        Ultimate
    } 
    
    [TestMethod]
    public void StringToEnumTest()
    {
          Assert.AreEqual(ProductVersion.Standard, "Standard".ToEnum<ProductVersion>());
    }

     

    4  数字类型上的扩展方法

    我这里有一个明显的例子是显示容量的扩展方法,请看下面的方法组:

    /// <summary> 
    /// Kilobytes 
    /// </summary> 
    /// <param name="value"></param> 
    /// <returns></returns> 
    public static int KB(this int value)
            {
                return value * 1024;
            }
    
    /// <summary> 
    /// Megabytes 
    /// </summary> 
    /// <param name="value"></param> 
    /// <returns></returns> 
    public static int MB(this int value)
            {
                return value.KB() * 1024;
            }
    
    /// <summary> 
    /// Gigabytes 
    /// </summary> 
    /// <param name="value"></param> 
    /// <returns></returns> 
    public static int GB(this int value)
            {
                return value.MB() * 1024;
            }
    
    /// <summary> 
    /// Terabytes 
    /// </summary> 
    /// <param name="value"></param> 
    /// <returns></returns> 
    public static long TB(this int value)
            {
                return (long)value.GB() * (long)1024;
            }
    

    用起来就很轻松了,简单的一行代码,获取容量的数字值

    var kb = 1.KB();
    var mb = 1.MB();
    var gb = 1.GB();
    var tb = 1.TB();

    最后一组扩展方法在计算百分比中经常遇到,比如统计计算,任务完成百分比计算:

     #region PercentageOf calculations
    
            /// <summary>
            /// The numbers percentage
            /// </summary>
            /// <param name="number">The number.</param>
            /// <param name="percent">The percent.</param>
            /// <returns>The result</returns>
            public static decimal PercentageOf(this int number, int percent)
            {
                return (decimal)(number * percent / 100);
            }
    
            /// <summary>
            /// Percentage of the number.
            /// </summary>
            /// <param name="percent">The percent</param>
            /// <param name="number">The Number</param>
            /// <returns>The result</returns>
            public static decimal PercentOf(this int position, int total)
            {
                decimal result = 0;
                if (position > 0 && total > 0)
                    result = (decimal)position / (decimal)total * 100;
                return result;
            }
            public static decimal PercentOf(this int? position, int total)
            {
                if (position == null) return 0;
                
                decimal result = 0;
                if (position > 0 && total > 0)
                    result = (decimal)((decimal)position / (decimal)total * 100);
                return result;
            }
    
            /// <summary>
            /// The numbers percentage
            /// </summary>
            /// <param name="number">The number.</param>
            /// <param name="percent">The percent.</param>
            /// <returns>The result</returns>
            public static decimal PercentageOf(this int number, float percent)
            {
                return (decimal)(number * percent / 100);
            }
    
            /// <summary>
            /// Percentage of the number.
            /// </summary>
            /// <param name="percent">The percent</param>
            /// <param name="number">The Number</param>
            /// <returns>The result</returns>
            public static decimal PercentOf(this int position, float total)
            {
                decimal result = 0;
                if (position > 0 && total > 0)
                    result = (decimal)((decimal)position / (decimal)total * 100);
                return result;
            }
    
            /// <summary>
            /// The numbers percentage
            /// </summary>
            /// <param name="number">The number.</param>
            /// <param name="percent">The percent.</param>
            /// <returns>The result</returns>
            public static decimal PercentageOf(this int number, double percent)
            {
                return (decimal)(number * percent / 100);
            }
    
            /// <summary>
            /// Percentage of the number.
            /// </summary>
            /// <param name="percent">The percent</param>
            /// <param name="number">The Number</param>
            /// <returns>The result</returns>
            public static decimal PercentOf(this int position, double total)
            {
                decimal result = 0;
                if (position > 0 && total > 0)
                    result = (decimal)((decimal)position / (decimal)total * 100);
                return result;
            }
    
            /// <summary>
            /// The numbers percentage
            /// </summary>
            /// <param name="number">The number.</param>
            /// <param name="percent">The percent.</param>
            /// <returns>The result</returns>
            public static decimal PercentageOf(this int number, decimal percent)
            {
                return (decimal)(number * percent / 100);
            }
    
            /// <summary>
            /// Percentage of the number.
            /// </summary>
            /// <param name="percent">The percent</param>
            /// <param name="number">The Number</param>
            /// <returns>The result</returns>
            public static decimal PercentOf(this int position, decimal total)
            {
                decimal result = 0;
                if (position > 0 && total > 0)
                    result = (decimal)position / (decimal)total * 100;
                return result;
            }
    
            /// <summary>
            /// The numbers percentage
            /// </summary>
            /// <param name="number">The number.</param>
            /// <param name="percent">The percent.</param>
            /// <returns>The result</returns>
            public static decimal PercentageOf(this int number, long percent)
            {
                return (decimal)(number * percent / 100);
            }
    
            /// <summary>
            /// Percentage of the number.
            /// </summary>
            /// <param name="percent">The percent</param>
            /// <param name="number">The Number</param>
            /// <returns>The result</returns>
            public static decimal PercentOf(this int position, long total)
            {
                decimal result = 0;
                if (position > 0 && total > 0)
                    result = (decimal)position / (decimal)total * 100;
                return result;
            }
    
            #endregion

     

    来看几个测试用例,增强对它的直观感受,因为涉及到的数值类型多一些,所以扩展方法的数量也多。

    Assert.AreEqual(33.0M, 100.PercentageOf(33));
    Assert.AreEqual(33.0M, 33.PercentOf(100));
    Assert.AreEqual(33.0M, 100.PercentageOf((float)33.0F));
    Assert.AreEqual(33.0M, 33.PercentOf((float)100.0F));
    Assert.AreEqual(33.0M, 100.PercentageOf((double)33.0F));
    Assert.AreEqual(33.0M, 33.PercentOf((double)100.0F));
    Assert.AreEqual(33.0M, 100.PercentageOf((decimal)33.0M));
    Assert.AreEqual(33.0M, 33.PercentOf((decimal)100.0M));
    Assert.AreEqual(33.0M, 100.PercentageOf((long)33));
    Assert.AreEqual(33.0M, 33.PercentOf((long)100));
  • 相关阅读:
    第五章:数组 结构体 和联合体
    第四章:用户自定义和枚举数据类型
    第三章:systemverilog文本值和数据类型
    阶段一:读几本经济学书
    第二章:systemverilog声明的位置
    数据结构-B树
    UDP的崛起
    vim使用
    sudo apt-get update
    计算机组成原理——浮点数表示方法
  • 原文地址:https://www.cnblogs.com/sczw-maqing/p/3190037.html
Copyright © 2011-2022 走看看