zoukankan      html  css  js  c++  java
  • Lambda的应用(转载)

    /// <summary>
            ///
    获取配置文件中DappSettings节点下指定索引键的Int类型的的值
           
    /// </summary>
            /// <param name="key">
    索引键</param>
            /// <param name="defaultValue">
    默认值</param>
            /// <returns>
    Int</returns>
           
    private static int getInt32(string key, int? defaultValue) {
               
    return getValue<int>(key, (v, pv) => int.TryParse(v, out pv), defaultValue);
            }
            private static T getValue<T>(string key, Func<string, T, bool> parseValue, T? defaultValue) where T : struct
            {
                string value = appSettings[key];
                if (value != null)
                {
                    T parsedValue = default(T);
    
                    if (parseValue(value, parsedValue))
                        return parsedValue;
                    else
                        throw new ApplicationException(string.Format("Settings '{0}' was not a valid {1}", key, typeof(T).FullName));
                }
                if (!defaultValue.HasValue)
                    throw new ApplicationException("在配置文件的appSettings节点结合中找不到key为" + key + "的子节点,且没有指定默认值");
                else
                    return defaultValue.Value;
            }

    该方法就是获取配置文件里相关的AppSetting项,并将其转换成Int32值.很不错的实现.但是实际上运行的时候却发现返回的值永远就是0,这不对啊.于是仔细的分析了这两个方法.主要就是利用了out关键字.

    我们知道,利用Out/Ref关键字,能使值类型的参数达到引用类型的参数的效果.

    瓦解黑盒子

    仔细分析了这两个方法.将核心实现重现如下

        public class MyClass
        {
            static int parseValue(string str, int pv)
            {
                if (ValidParse(str, pv))
                    return pv;
                else
                    return 0;
            }
    
            static bool ValidParse(string str, int input)
            {
                return Int32.TryParse(str, out input);
            }
    
    
            public static void Main()
            {
                string str = "100";
                int num = 0;
                Console.WriteLine(parseValue(str, num));
            }
    
        }

    看得到.调用步骤如下Main->parseValue->ValidParse,Main得到了一个字符串变量,想把它转换成Int类型,于是找到了parseValue方法.parseValue方法要求Main提供字符串和一个Int变量,它的做法是利用ValidParse方法,尝试能否吧str转换成Int,如果可以的话就返回Int,注意!此处的原意和TryParse相识.而ValidParse方法就是简单的调用了TryParse.大体看下来.这个流程是没什么问题的.而且应该得到正确的答案.但事实却并非如此.图解一下

    image

    可能图画得不太精确.但能诠释这个过程就好了.调用的过程.

    第一步.看到.str是引用过去了.而num并不是原值,而是做了一个副本拷贝.这样.即使在parseValue中num的值发生改变.也只是副本数据发生了改变.

    第二步.可以看到.str还是引用,即保持第一手数据.而num又做了一次副本拷贝.在validParse上调用了TryParse方法.此时,ValidParse上的num改变了.但是注意.此处也是副本修改.所以.

    第三步(返回),num数据丢失.这也就解释了为什么我们的结果总会是0了.

    既然知道了原因.那就好办了.我们尝试着加上out

        public class MyClass
        {
            static int parseValue(string str, int pv)
            {
                if (ValidParse(str, out pv))
                    return pv;
                else
                    return 0;
            }
    
            static bool ValidParse(string str, out int input)
            {
                return Int32.TryParse(str, out input);
            }
    
    
            public static void Main()
            {
                string str = "100";
                int num = 0;
                Console.WriteLine(parseValue(str, num));
            }
    
        }

    改动并不大.只是在第二步中调用加入out,但是恰是这个out.让我们的结果正确了.原因就是第三步使用的num并不是步骤二的副本.而是步骤二的数据.所以它修改了原数据,没发生数据丢失.

    优化代码

    精简代码一向是我们所追崇的.特别是.Net3.5之后的Lambda.不用的话岂不浪费.废话不多说.我们开工

    delegate bool ParseFunc<T, S>(T T1, out S S1); 

    先声明一个委托,注意,这里的委托中用到了out.

            private static T getOutValue<T>(string key, ParseFunc<string,T> parseValue, T? defaultValue) where T : struct
            {
                string value = appSettings[key];
                if (value != null)
                {
                    T parsedValue = default(T);
    
                    if (parseValue(value, out parsedValue))
                        return parsedValue;
                    else
                        throw new ApplicationException(string.Format("Settings '{0}' was not a valid {1}", key, typeof(T).FullName));
                }
                if (!defaultValue.HasValue)
                    throw new ApplicationException("在配置文件的appSettings节点结合中找不到key为" + key + "的子节点,且没有指定默认值");
                else
                    return defaultValue.Value;
            }

    再改造一下GetValue方法.此处必须注意的是,在传参时必须使用Out,当然.你没用out,编译器也不会让你通过.最后

            public static int getInt32(string key, int? defaultValue)
            {
                return getOutValue<int>(key, (string v, out int pv) => int.TryParse(v, out pv), defaultValue);
            }转自:http://www.cnblogs.com/kongyiyun/archive/2010/12/03/1895764.html
  • 相关阅读:
    Windows下 如何添加开机启动项
    Android在 普通类(非Activity,多数为Adapter) 中 传输数据为空值 解决方法 :在startActivity 用 intent传输数据
    Android 从ImageView中获取Bitmap对象方法
    剑指offer(纪念版)读书笔记【实时更新】
    剑指offer(纪念版) 面试题3:二维数组中的查找
    C++ sizeof 误区 大公司面试题
    51 nod 1521 一维战舰 时间复杂度O(n),同 Codeforces 567D. One-Dimensional Battle Ships 有详细注释
    51nod 1126 求递推序列的第N项 思路:递推模拟,求循环节。详细注释
    51nod 1451 合法三角形 判斜率去重,时间复杂度O(n^2)
    关于JetBrains CLion 激活 (CLion License Activation)的解决办法,带hosts详细修改
  • 原文地址:https://www.cnblogs.com/johnwonder/p/1906087.html
Copyright © 2011-2022 走看看