一種優雅的條件引用第三方.net庫的方法


1.遇到的問題 

今年我一直在開發一個WebApiClient庫,旨在.net下能像java的retrofit一樣,方便地請求服務端的http接口。在這restful api盛行的年代,json的身影無處不在,.net framework自然也有json庫,System.Web.Script.Serialization.JavaScriptSerializer就是其中一個,但綜合性較好的,還是第三方的json.net。在開發WebApiClient過程中,我一直沒有依賴json.net,原因是:如果我的WebApiClient依賴json.net的版本是6.0,某個第三方庫ThirdLib依賴的json.net版本是7.0,在項目中會無法都使用WebApiClient和ThirdLib,原因是他們依賴的json.net版本不一樣而決生沖突,給使用者解決起來很非常麻煩。

2.期望的效果

我期望的效果是,如果引用WebApiClient庫的項目有使用到json.net,那么WebApiClient在json序列化時,就使用json.net,否則使用.net framework的System.Web.Script.Serialization.JavaScriptSerializer。這就要求我在開發WebApiClient的時候,不能直接引用json.net來開發,只能在運行時檢測應用程序域是否已加載了json.net,從而反射調用json.net來進行序列化。

想要的效果是這樣的

/// <summary>
/// 反序列化對象
/// </summary>
/// <param name="json">json</param>
/// <param name="objType">對象類型</param>
/// <returns></returns>
public object Deserialize(string json, Type objType)
{
    if (string.IsNullOrEmpty(json))
    {
        return null;
    }

    if (JsonNet.IsSupported == true)
    {
        return JsonNet.DeserializeObject(json, objType);
    }

    var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
    return serializer.Deserialize(json, objType);
}

 

3.解決的方案

在運行時檢測應用程序域是否已加載了json.net,從而反射調用json.net來進行序列化。

實現中的難點:

1、如果檢測是否加載了Json.net

2、在檢測之后,才加載Json.net怎么辦

3、怎么樣減少反射的性能損耗

 

難點的解決:

1、使用AppDomain.CurrentDomain.GetAssemblies()方法獲取當前程序域目前已加載的程序集,判斷是否有Json.net的程序集;

2、監聽AppDomain.CurrentDomain.AssemblyLoad事件,訂閱新加載的程序集是否為Json.net的程序集;

3、將Newtonsoft.Json.JsonConvert的SerializeObject和DeserializeObject方法生成強類型委托,緩存起來等待調用;

 

完整代碼實現:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace WebApiClient
{
    /// <summary>
    /// 提供Json.net無引用調用
    /// </summary>
    static class JsonNet
    {
        /// <summary>
        /// Json.Net程序集名稱
        /// </summary>
        private static readonly string jsonNetAssemblyName = "Newtonsoft.Json";

        /// <summary>
        /// JsonConvert類名
        /// </summary>
        private static readonly string jsonNetJsonConvertTypeName = "Newtonsoft.Json.JsonConvert";

        /// <summary>
        /// 序列化方法的委托
        /// </summary>
        private static Func<object, string> serializeFunc = null;

        /// <summary>
        /// 反序列化方法的委托
        /// </summary>
        private static Func<string, Type, object> deserializeFunc = null;

        /// <summary>
        /// 獲取是否得到支持
        /// </summary>
        public static bool IsSupported = false;

        /// <summary>
        /// Json.net
        /// </summary>
        static JsonNet()
        {
            AppDomain.CurrentDomain.AssemblyLoad += (s, e) => InitJsonNet(e.LoadedAssembly);
            InitJsonNet(AppDomain.CurrentDomain.GetAssemblies());
        }

        /// <summary>
        /// 序列化對象
        /// </summary>
        /// <param name="obj">對象</param>
        /// <returns></returns>
        public static string SerializeObject(object obj)
        {
            return JsonNet.serializeFunc.Invoke(obj);
        }

        /// <summary>
        /// 反序列化為對象
        /// </summary>
        /// <param name="json">json文本</param>
        /// <param name="type">對象類型</param>
        /// <returns></returns>
        public static object DeserializeObject(string json, Type type)
        {
            return JsonNet.deserializeFunc.Invoke(json, type);
        }

        /// <summary>
        /// 初始化json.net
        /// </summary>
        /// <param name="assemblies">查找的程序集</param>
        private static void InitJsonNet(params Assembly[] assemblies)
        {
            if (JsonNet.IsSupported == true)
            {
                return;
            }

            var jsonNetAssembly = assemblies
                .FirstOrDefault(item => item.GetName().Name.Equals(jsonNetAssemblyName, StringComparison.OrdinalIgnoreCase));

            if (jsonNetAssembly == null)
            {
                return;
            }

            var jsonConvertType = jsonNetAssembly.GetType(jsonNetJsonConvertTypeName, false);
            if (jsonConvertType == null)
            {
                return;
            }

            serializeFunc = CreateSerializeObjectFunc(jsonConvertType);
            deserializeFunc = CreateDeserializeObjectFunc(jsonConvertType);
            JsonNet.IsSupported = serializeFunc != null && deserializeFunc != null;
        }

        /// <summary>
        /// 創建SerializeObject方法的委托
        /// </summary>
        /// <param name="classType">JsonConvert類型</param>
        /// <returns></returns>
        private static Func<object, string> CreateSerializeObjectFunc(Type classType)
        {
            var method = classType.GetMethod("SerializeObject", new[] { typeof(object) });
            if (method == null)
            {
                return null;
            }
            return (Func<object, string>)method.CreateDelegate(typeof(Func<object, string>));
        }

        /// <summary>
        /// 創建DeserializeObject方法的委托
        /// </summary>
        /// <param name="classType">JsonConvert類型</param>
        /// <returns></returns>
        private static Func<string, Type, object> CreateDeserializeObjectFunc(Type classType)
        {
            var method = classType.GetMethod("DeserializeObject", new[] { typeof(string), typeof(Type) });
            if (method == null)
            {
                return null;
            }
            return (Func<string, Type, object>)method.CreateDelegate(typeof(Func<string, Type, object>));
        }
    }
}

 

關於WebApiClient

這是一個讓你描述做什么請求,而不是叫你如何請求的httpClient客戶端項目,關注一下,你會眼前一亮,get到新思想。

github:https://github.com/xljiulang/WebApiClient

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM