【fixed point】柯里化,currying C#实现

参考文章:http://www.mamicode.com/info-detail-1076478.html

函数调用的演变:

 /// <summary>
    /// 柯里化的演变
    /// </summary>
    public class Currying
    {
        CurryingSdkApi api = new CurryingSdkApi();

        public string callApi()
        {
            var result = string.Empty;


            //假如现在我们基于某个sdk开发一个app,需要调用该sdk提供的api,这些api都有3个参数,分别是调用你的app的id,用户的id和用户的nickname
            result = api.SdkApiFirst("myApp", "xiaoming", "小明");
            result = api.SdkApiFirst("myApp", "xiaohong", "小红");
            result = api.SdkApiFirst("myApp", "xiaogang", "小刚");

            //这时候你可能发现了一些端倪,代码中出现了重复的部分(你的app的id),这时候重构代码把公共的部分抽取出来,你可能会这么封装
            result = MyApiFirst("xiaoming", "小明");
            result = MyApiFirst("xiaohong", "");
            result = MyApiFirst("xiaogang", "小刚");

            //然后你继续开发,发现要调用另外一个api,这个api跟上面那个很相似,只是第2、3个参数变为了用户的令牌和用户id。因为你的app的id是不变的,有了之前的经验,你或许会这么封装。
            result = MyApiSecond(1, "xiaoming");
            result = MyApiSecond(2, "xiaohong");
            result = MyApiSecond(3, "xiaogang");

            //继续开发的时候,你很有可能会继续调用类似的api3,api4,api5......,这些api的第一个参数都是你的app的id,而在你的某个项目里面,这都是固定不变,那么你的程序里面会出现类似的封装,可以看出又有了重复的代码
            //此时你或许会这么封装去减少重复

            var myapi1 = api.SdkApiSeriesFirst(api.SdkApiFirst);
            result = myapi1(string.Empty, "xiaoming", "小红");

            var myapi2_1 = api.GetMyDefaultApi<string, string, string>(api.SdkApiFirst);
            result = myapi2_1("xiaoming", "小红");

            var myapi2_2 = api.GetMyDefaultApi<int, string, string>(api.SdkApiSecond);
            result = myapi2_2(2, "xiaogang");

            var myapi3 = api.SdkApiSeriesFirstPlus(api.SdkApiFirst);
            result = myapi3("xiaoming", "小红");


            return result;
        }

        public string MyApiFirst(string userId, string nickname)
        {
            return api.SdkApiFirst("myApp", userId, nickname);
        }

        public string MyApiSecond(int token, string userId)
        {
            return api.SdkApiSecond("myApp", token, userId);
        }
    }

假设的API接口:

 public class CurryingSdkApi
    {
        /// <summary>
        /// 软件开发工具包(第一个API)
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="userId"></param>
        /// <param name="nickname"></param>
        /// <returns></returns>
        public string SdkApiFirst(string appId, string userId, string nickname)
        {
            return "SdkApiFirst " + appId + userId + nickname;
        }


        /// <summary>
        /// 软件开发工具包(第二个API)
        /// </summary>
        /// <param name="appId"></param>
        /// <param name="token"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public string SdkApiSecond(string appId, int token, string userId)
        {
            return "SdkApiSecond " + appId + token + userId;
        }


        public Func<string, string, string, string> SdkApiSeriesFirst(Func<string, string, string, string> f)
        {
            return (x, y, z) => f("myApp", y, z);
        }


        public Func<string, string, string> SdkApiSeriesFirstPlus(Func<string, string, string, string> f)
        {
            return (x, y) => f("myApp", x, y);
        }

        public Func<string, string> SdkApiSeriesSecond(Func<string, string, string, string> f)
        {
            return (x) => f("myApp", "myAppName", x);
        }

        public Func<T1, T2, TResult> GetMyDefaultApi<T1, T2, TResult>(Func<string, T1, T2, TResult> f)
        {
            return (x, y) => f("myApp", x, y);
        }
    }

关键点:

下面是匿名函数, a,b 是 参数

(a,b) => {  实现方法内容  };

可以,封装一个三个参数的方法为两个参数的方法

 public Func<string, string, string, string> SdkApiSeriesFirst(Func<string, string, string, string> f)
        {
            return (x, y, z) => f("myApp", y, z);
        }