『飞秋』在.NET 4中调用GDAL库时遇到的问题及解决方法

最近需要在.NET 4的环境中调用GDAL库。GDAL本身是一套非托管类库,不过还好提供了用SWIG做的托管的Wrapper。

可以在FWTools的安装包中找到这些Wrapper的编译好的dll文件,不过FWTools中附带的版本依赖于gdal_fw.dll(gdal_fw.dll是GDAL核心类库的修改版),而gdal_fw.dll依赖的其他非托管程序集太多了,加起来有18M左右。所以还是自己下载代码编译的好。

这篇文章介绍了1.4版本的下载和编译方法,该方法同样适用于现在最新的1.7版本。

编译好之后引用、调用、Debug都没问题,一切正常,但是如果用Release编译并在VS之外运行的话则会报出AccessViolationException,异常信息提示说访问了受保护的内存。我的第一反应就是托管的Wrapper中用P/Invoke调用了非托管程序集,而非托管程序集导致了这个问题。但是这个猜测并不能解释为什么只有在.NET 4+Release+IDE外运行的情况下才会出错的现象。

猜来猜去,找来找去找到了问题的所在:

GDAL的托管Wrapper中有一个叫做SWIGStringHelper的类型,该类型的静态构造方法中执行了一些比较重要的初始化操作。另外一个叫做OsrPINVOKE的类中声明了一个SWIGStringHelper类型的私有静态字段,并在声明时就new了该字段,而且OsrPINVOKE中没有显式声明的静态构造。

把这两个类型的代码简化一下的话,大概是这样的:

view sourceprint?01 class OsrPINVOKE

02     {

03         private static SWIGStringHelper helper = newSWIGStringHelper();

04

05         public static void DoSomething()

06         {

07            Console.WriteLine("static method of OsrPINVOKE");

08         }

09     }

10

11     class SWIGStringHelper

12     {

13         static SWIGStringHelper()

14         {

15            //这里做了一些重要的初始化

16            Console.WriteLine("SWIGStringHelper static constructor");

17         }

18 }

如果有代码调用DoSomething,这段代码执行顺序估计是这样的:

OsrPINVOKE的静态构造方法(里面初始化helper这个静态字段);

SWIGStringHelper的静态构造方法(输出字符串);

SWIGStringHelper的实例构造方法(里面啥也没有做);

DoSomething方法(输出字符串)。

所以应该是先输出SWIGStringHelperstatic constructor而后输出static method ofOsrPINVOKE。

试着用下面的代码调用一下:

view sourceprint?1 static void Main(string[] args)

2         {

3             OsrPINVOKE.DoSomething();

4             Console.ReadLine();

5         }

却发现如果用的target framework是.net4,用release编译并且在VS外运行的话,就会只输出static method of OsrPINVOKE,感觉好像SWIGStringHelper的静态构造方法没有执行。而如果用的是.net 2.0、3.5,或者是用Debug编译或是在VS里面运行的话输出结果都和预期的一致。

难道是静态字段的初始化在.NET 4中变成Lazy的了?

事实证明真的是这样:

如果一个类型提供了显式声明的静态构造的话,那么这个静态构造方法会在创建该类型实例或者访问该类型的任何静态成员之前被执行。

如果一个类型没有提供显式声明的静态构造的话,编译器会自动给该类型一个默认的静态构造,并把静态字段的初始化都放到该默认静态构造中去,而这个默认的静态构造只会在静态字段被访问时才执行,也就是说创建实例、调用实例方法、调用静态方法时都不会触发静态构造的执行(当然前提是它们没有访问静态字段)。

不过CLR在加载一个类型时怎么知道其中包含的静态构造方法是编译器加上的还是原C#代码中显式提供的呢?事实上这是beforefieldinit的作用。

根据上面的原则再来分析一下:OsrPINVOKE中没有显式声明的静态构造,所以编译器会生成一个默认的静态构造并把helper的实例创建放入其中。而这个默认的静态构造只会在helper这个唯一的静态字段被访问时才会执行。而代码中没有任何地方访问了helper,所以OsrPINVOKE的静态构造根本就没有执行,helper根本就没有被new出来,SWIGStringHelper的静态构造自然也就没有执行。

所以要解决这个问题的话只要在OsrPINVOKE里面显式声明一个静态构造方法,把new SWIGStringHelper();这一句放到里面,或者仅仅是显式声明一个静态构造并把它留空。然后重新编译一下GDAL的Wrapper就可以了。

如果您也在.NET 4中调用GDAL时遇到了类似的问题,不妨试一下这种解决方法。

其实不仅是GDAL,其他由SWIG制作的托管Wrapper估计都会受到影响。

参考:飞秋官网:http://www.freeeim.com/

『飞秋』在.NET 4中调用GDAL库时遇到的问题及解决方法相关推荐

  1. 在pytorch环境中调用SRU模块时出现的问题及解决方法

    1. pytorch环境配置 参考:Windows 10系统在Anaconda下安装GPU版Pytorch 期间,电脑正常联网下载pytorch特别特别慢,参考:pytorch下载太慢的解决办法 pi ...

  2. 『飞秋』Windows7新功能体验(1):为Windows 7 Media Center安装网络电视(Internet TV)

    『飞秋』Windows7新功能体验(1):为Windows 7 Media Center安装网络电视(Internet TV) 在Windows 7许多的新功能里,娱乐功能也做了很大的改进: Dire ...

  3. 『飞秋』关于ASP.NET MVC+Repository+Service架构的一些思考

    『飞秋』关于ASP.NET MVC+Repository+Service架构的一些思考 看了一些ASP.NET MVC开源项目后的一些想法,关于ASP.NET MVC+Repository+Servi ...

  4. 『飞秋』小项目心得交流

    『飞秋』小项目心得交流 <!--[endif]--> 最近网站首页改版,我负责前台页面的编写,一个很小的任务,从中我却学习到了很多东西,现总结一下 和大家分享一下,希望对大家有用,也希望能 ...

  5. 『飞秋』在ASP.NET服务器端过程中使用WebBrowser的注意事项

    昨天刚刚完成了一个从网页上提取内容的ASP.NET程序.因为目标网页内容比较复杂,所以采用了WebBrowser来代替WebClient. 但是,在本地写好的程序,放到了服务器上就停止工作了,也找不到 ...

  6. 『飞秋』测试驱动开发TDD系列(二)

    引言 今天我们来做一个TDD的小例子.通过一个栈的实现来体验一下TDD的过程.在本系列的代码示例中,使用VS2010作为IDE工具,NUnit作为测试辅助工具.关于NUnit的使用,在园子中已经有很多 ...

  7. 『飞秋』WCF热门问题编程示例

    WCF热门问题编程示例(4):WCF客户端如何异步调用WCF服务? Posted on 2010-08-01 14:28 Frank Xu Lei 阅读(296) 评论(3) 编辑 收藏 所属分类: ...

  8. 『飞秋』Html.Label的缺陷及补救办法

    在最近开发的项目中,应用了Html.LabelFor(TModel)来生成<lable/>标签,同时配合Html.TextBoxFor(TModel)来生成<Input/>标签 ...

  9. vue项目中使用组件库设置样式不生效的解决方法

    scoped 实现原理 实现组件的私有化,不对全局造成样式污染 ,我们使用scoped 作用:声明的样式只对当前组件生效 <style lang="less" scoped& ...

最新文章

  1. 带花树[一般图最大匹配模板]
  2. RabbitMQ 的引言
  3. Spring Cloud Feign 请求压缩 、Feign的日志级别配置
  4. JDK Executor执行器的应用
  5. navicat存储过程返回值为空_Excel VBA解读(128):Function过程详解——枯燥的语法...
  6. PHP文件系统-文件的读写操作
  7. 数据库索引系列四:索引算法Hash与BTree的区别
  8. table中强制不换行
  9. dosbox中out of memory_flink教程-详解flink 1.11 中的JDBC Catalog
  10. HackerRank Twin Arrays 题解
  11. Tomcat9的安装及配置详细步骤
  12. 魔兽争霸III背景渊源
  13. 数据结构-左倾红黑树
  14. java整形数组的最大最小值
  15. oracle增加字段为主键自增_Oracle新增自增一的主键字段和赋值代码
  16. Windows 局域网中文件进行自动同步备份通过synctoy和计划任务实现
  17. RK3288源码编译
  18. ArcGIS中矢量裁剪栅格影像及影像合并【附练习数据下载】
  19. 即速应用——不会代码也能做App
  20. 乳腺癌(Breast cancer)数据集———Breakhis分享

热门文章

  1. linux组的管理命令,linux 用户和组管理命令(示例代码)
  2. ElasticSearch手动创建mapping
  3. 互联网晚报 | 11月21日 星期日 | B站公布《三体》动画首个预告片;涪陵榨菜回应天价礼盒;农行个人贷款余额突破7万亿元...
  4. 用SWOT模型剖析SaaS
  5. 给年份year,定义一个宏,以判别该年份是否闰年。提示:宏名可以定义为LEAP_YEAR,形参为y,既定义宏的形式为 #define LEAP_YEAR(y) (读者设计的字符串)
  6. 电钻有刷好还是无刷好_高中物理好的来看看,永磁同步直流电机是怎样实现无刷驱动的?...
  7. 感恩有您!《大数据》祝您新年快乐!
  8. 作者:赵菁华(1977-),女,中国电子技术标准化研究院高级工程师。
  9. 王融(1979-),女,中国信息通信研究院互联网法律中心副主任、高级工程师...
  10. 使用双指针可能只需要遍历一趟哦(洛谷P1147题题解,Java语言描述)