命名空间冲突

最近在项目上使用 Ozeki SDK 的时候遇到版本冲突的问题,冲突库是 Newtonsoft.Json ,主要因为 Ozeki SDK 把 Newtonsoft.Json 1.0.x 嵌入了,而我的项目里引用的是 Newtonsoft.Json 11.0.2 ,在使用相关对象时编译器报错:

The type 'JsonConvert' exists in both 'XXX.XXX, Version=1.0.0.0, 
Culture=neutral, PublicKeyToken=...' and 'Newtonsoft.Json, Version
=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'

然后 Baidu 了下,搜到的解决办法竟然是在 App.config 中添加类似以下一段代码

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

鄙人试了一下,尝试改了改 publicKeyToken,又尝试改了改 oldVersion,又尝试改了改 newVersion,还是不管用。这段什么意思呢?读者有心可以查阅官方文档 assemblyBinding MSDN

总之,是复杂复杂滴!!我们遇到的是什么问题呢,是同一个DLL不同版本互相冲突?还是程序集版本需要重定向?

实际我看了下官方文档,因为没代码例子,也不知这种重定向主要是解决什么问题的,读书的时候没学过,老师也没教过啊... ...但是不打紧,接下来就该打脸了。

这归根结底是命名空间冲突,晴树SEU 的《命名空间namespace ,以及重复定义的问题解析》 提到:

名字空间是用来划分冲突域的,把全局名字空间划分成几个小的名字空间。全局函数,全局变量,
以及类的名字是在同一个全局名字空间中,有时为了防止命名冲突,会把这些名字放到不同的名
字空间中去。

重定向学校老师没教过,命名空间的使用总教过吧,全局命名空间啊,你把它...把它...交还给老师啦??!!!

比方说,我们现在有个项目A 引用了 Newtonsoft.Json 最新版,然后项目A 需要引用项目B ,但是项目B 中有如下代码(具体来讲是命名空间)导致项目A 与原本正在使用的 Newtonsoft.Json 库的相关命名空间冲突:

using System;

namespace Newtonsoft.Json
{
    public class JsonConvert
    {
        public string SerializeObject(object value)
        {
            throw new NotImplementedException();
        }
    }
}

解决办法其实很简单,把后来者(程序集)加别名,用全局命名空间就可以区分开这些相同的命名空间,就不会影响项目对之前库的引用。

具体操作如下:

1、给后来者程序集加别名。

2、使用 extern alias 关键字来引用项目B 中的相关对象。

extern alias LibX;

using Newtonsoft.Json;

namespace DemoLibConflict.ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var emp = new Employee { Name = "Tom" };
            
            //假设这是项目正在使用 Newtonsoft.Json 库的代码。
            string json = JsonConvert.SerializeObject(emp);

            //假设这行是新增引用项目B 后使用的代码。
            string json2 = LibX::Newtonsoft.Json.JsonConvert.SerializeObject(emp);
        }
    }

    public class Employee
    {
        public string Name { get; set; }
    }
}

这样就可以避免与其他命名空间冲突。

 

参考资料:

晴树SEU 的《命名空间namespace ,以及重复定义的问题解析》

Type exists in 2 assemblies in StackOverflow


版权声明:本文为doncle000原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。