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

 

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

这些托管的程序集被包含在了FWTools的安装包中,FWTools中带的版本依赖于gdal_fw.dllgdal_fw.dllGDAL核心类库的修改版,而它依赖的其他非托管程序集太多了,加起来有18M左右。所以还是自己下载代码编译的好。

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

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

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

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

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

class OsrPINVOKE { private static SWIGStringHelper helper = new SWIGStringHelper(); public static void DoSomething() { Console.WriteLine("static method of OsrPINVOKE"); } } class SWIGStringHelper { static SWIGStringHelper() { //这里做了一些重要的初始化 Console.WriteLine("SWIGStringHelper static constructor"); } }

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

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

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

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

DoSomething方法(输出字符串)。

所以应该是先输出SWIGStringHelper static constructor而后输出static method of OsrPINVOKE

试着这样调用一下:

static void Main(string[] args) { OsrPINVOKE.DoSomething(); Console.ReadLine(); } 

却发现如果用的target framework.net 4,用release编译并且在VS外运行的话,就会只输出static method of OsrPINVOKE,感觉好像SWIGStringHelper的静态构造方法没有执行。而如果用的是.net 2.03.5,或者是用Debug编译或是在VS里面运行的话都不会有问题。

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

事实证明真的是这样。所以要解决这个问题的话只要在OsrPINVOKE里面显示声明一个静态构造方法,把new SWIGStringHelper();这一句放到里执行就OK了。

如果您在.NET 4中调用GDAL时遇到了类似的问题,不妨试一下。

 

参考:

http://social.microsoft.com/Forums/zh-CN/visualcshartzhchs/thread/2106ea8e-4889-45bf-82fd-55ab4b3e9aad

http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/d3fb3454-b982-4357-bb6b-63f7eceee69b/#96f5cc6b-a31b-4ae2-b2f4-40a99e7581af

 

感谢:

韦恩卑鄙Nishant Sivakumar

 

你可能感兴趣的:(.net,String,Class,ide,Constructor,wrapper)