一种优雅的条件引用第三方.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

原文地址:https://www.cnblogs.com/kewei/p/8228343.html

时间: 2024-10-07 22:27:09

一种优雅的条件引用第三方.net库的方法的相关文章

android so库多平台引用第三方so库,及多平台编译

1, eclipse 新建android项目,添加jni目录,配置ndk 2,jni目录下新建第三方库的引用源文件目录,包含各个平台的so包以及对应的头文件 3,配置Android.mk 第三方库引用的配置文件如: LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := 引用库别名 LOCAL_SRC_FILES :=$(TARGET_ARCH_ABI)/引用库文件名称.so include $(PREBUILT_SH

css引用第三方字体库

对应的CSS文件中如下方式进行字体库的引用: @font-face { font-family: '造字工房情书'; src: url('../fonts/MFQingShu_Noncommercial-Regular.otf'); } .website-purpose { color: white; font-size: 1.5em; font-family: '造字工房情书'; text-align: center; padding-top: 0.8em; letter-spacing: 5

vs增加第三方依赖库的方法总结

转自http://blog.csdn.net/raodotcong/article/details/8998379 先说说普通的两种方法: 方法1:  通过设置工程配置来添加lib库. 转自网上: A.添加工程的头文件目录:工程---属性---配置属性---c/c++---常规---附加包含目录:加上头文件存放目录. B.添加文件引用的lib静态库路径:工程---属性---配置属性---链接器---常规---附加库目录:加上lib文件存放目录.C  然后添加工程引用的lib文件名:工程---属性

Cocos2dx如何引用第三方SO文件(Android NDK)

做项目的过程中发现,引用第三方的库lib3rdsdk.so,当直接把lib3rdsdk.so放进armeabi文件夹里,会被删除掉.查网上资料都说的不全,经过实验,最简单的方法就是在jni下的android.mk里加下面3-7行就可以,要放最前面,放后面有可能不行哦,因为编译路径有可能会被改掉. 其中prebuilt/$(TARGET_ARCH_ABI)中的prebuilt就是jni里新建的prebuilt文件,其实建不建无所谓,prebuilt里面有4个文件夹:armeabi.armeabi-

IOS 编程中引用第三方的方类库的方法及常见问题(转载)

//原文:http://www.th7.cn/Program/IOS/201407/244585.shtml 方法一:直接复制所有源文件到项目中 这种方法就是把第三方类库的所有源文件复制到项目中,直接把所有.h和.m文件拖到XCode项目中即可. 注意: 1. 如果第三方类库引用了一些系统自带类库,那么在项目中还需要额外引用那些类库. 2. 如果当前的项目启用了ARC,而引用的第三方类库未使用ARC,那还需要在项目信息的Targets – Build Parses 里找到第三方类库的.m文件,并

IOS 编程中引用第三方的方类库的方法及常见问题

方法一:直接复制所有源文件到项目中 这种方法就是把第三方类库的所有源文件复制到项目中,直接把所有.h和.m文件拖到XCode项目中即可. 注意: 1. 如果第三方类库引用了一些系统自带类库,那么在项目中还需要额外引用那些类库. 2. 如果当前的项目启用了ARC,而引用的第三方类库未使用ARC,那还需要在项目信息的Targets – Build Parses 里找到第三方类库的.m文件,并为它们加上-fno-objc-arc标记. 3. 对于在未启用ARC的项目用引用使用了ARC的第三方类库,则需

APK中引用第三方库文件

注意以下操作是在源码中进行,即修改Android.mk,并非借助IDE(AndroidStudio)的情形. 引用第三方JAR包 1,在源Android.mk里面加参数,使其编译为JAR包,然后mm编译 ... LOCAL_MODULE_CLASS := JAVA_LIBRARIES include $(BUILD_JAVA_LIBRARY) ... 2,提取class.jar选用 把common下面的jar包文件(out\target\common\obj\JAVA_LIBRARIES\xxx

Android Studio工程引用第三方so文件

应用程序二进制接口(Application Binary Interface)定义了二进制文件(尤其是.so文件)如何运行在相应的系统平台上,从使用的指令集,内存对齐到可用的系统函数库.在Android 系统上,每一个CPU架构对应一个ABI:armeabi,armeabi-v7a,x86,mips,arm64- v8a,mips64,x86_64. so文件和jar包存放到工程的libs目录下.p.s.另外,可以将apk解压出来,查看lib目录,也能分析该apk的so文件目录. 使用 app源

DOS环境下含包并引用第三方jar的java程序的编译及运行

DOS环境下含包并引用第三方jar的java程序的编译及运行 1.程序目录机构 bin:class文件生成目录 lib:第三方jar包目录 src:源程序文件目录 2.程序代码: 3.程序编译 javac –classpath .;..\lib\commons-lang-2.3.jar -d ..\bin com\Test.java 4.编译后的程序目录: 5.运行程序及结果显示 java -classpath .;..\lib\commons-lang-2.3.jar com.Test