日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

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

發(fā)布時間:2025/3/15 asp.net 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 『飞秋』在.NET 4中调用GDAL库时遇到的问题及解决方法 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

『飛秋』在.NET 4中調(diào)用GDAL庫時遇到的問題及解決方法

最近需要在.NET 4的環(huán)境中調(diào)用GDAL庫。GDAL本身是一套非托管類庫,不過還好提供了用SWIG做的托管的Wrapper。

可以在FWTools的安裝包中找到這些Wrapper的編譯好的dll文件,不過FWTools中附帶的版本依賴于gdal_fw.dll(gdal_fw.dll是GDAL核心類庫的修改版),而gdal_fw.dll依賴的其他非托管程序集太多了,加起來有18M左右。所以還是自己下載代碼編譯的好。

這篇文章介紹了1.4版本的下載和編譯方法,該方法同樣適用于現(xiàn)在最新的1.7版本。

編譯好之后引用、調(diào)用、Debug都沒問題,一切正常,但是如果用Release編譯并在VS之外運行的話則會報出AccessViolationException,異常信息提示說訪問了受保護(hù)的內(nèi)存。我的第一反應(yīng)就是托管的Wrapper中用P/Invoke調(diào)用了非托管程序集,而非托管程序集導(dǎo)致了這個問題。但是這個猜測并不能解釋為什么只有在.NET 4+Release+IDE外運行的情況下才會出錯的現(xiàn)象。

猜來猜去,找來找去找到了問題的所在:

GDAL的托管Wrapper中有一個叫做SWIGStringHelper的類型,該類型的靜態(tài)構(gòu)造方法中執(zhí)行了一些比較重要的初始化操作。另外一個叫做OsrPINVOKE的類中聲明了一個SWIGStringHelper類型的私有靜態(tài)字段,并在聲明時就new了該字段,而且OsrPINVOKE中沒有顯式聲明的靜態(tài)構(gòu)造。

把這兩個類型的代碼簡化一下的話,大概是這樣的:


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 }


如果有代碼調(diào)用DoSomething,這段代碼執(zhí)行順序估計是這樣的:

OsrPINVOKE的靜態(tài)構(gòu)造方法(里面初始化helper這個靜態(tài)字段);

SWIGStringHelper的靜態(tài)構(gòu)造方法(輸出字符串);

SWIGStringHelper的實例構(gòu)造方法(里面啥也沒有做);

DoSomething方法(輸出字符串)。

所以應(yīng)該是先輸出SWIGStringHelperstatic constructor而后輸出static method ofOsrPINVOKE。

試著用下面的代碼調(diào)用一下:


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

2???????? {?

3???????????? OsrPINVOKE.DoSomething();?

4???????????? Console.ReadLine();?

5???????? }


卻發(fā)現(xiàn)如果用的target framework是.net4,用release編譯并且在VS外運行的話,就會只輸出static method of OsrPINVOKE,感覺好像SWIGStringHelper的靜態(tài)構(gòu)造方法沒有執(zhí)行。而如果用的是.net 2.0、3.5,或者是用Debug編譯或是在VS里面運行的話輸出結(jié)果都和預(yù)期的一致。

難道是靜態(tài)字段的初始化在.NET 4中變成Lazy的了?

事實證明真的是這樣:

如果一個類型提供了顯式聲明的靜態(tài)構(gòu)造的話,那么這個靜態(tài)構(gòu)造方法會在創(chuàng)建該類型實例或者訪問該類型的任何靜態(tài)成員之前被執(zhí)行。

如果一個類型沒有提供顯式聲明的靜態(tài)構(gòu)造的話,編譯器會自動給該類型一個默認(rèn)的靜態(tài)構(gòu)造,并把靜態(tài)字段的初始化都放到該默認(rèn)靜態(tài)構(gòu)造中去,而這個默認(rèn)的靜態(tài)構(gòu)造只會在靜態(tài)字段被訪問時才執(zhí)行,也就是說創(chuàng)建實例、調(diào)用實例方法、調(diào)用靜態(tài)方法時都不會觸發(fā)靜態(tài)構(gòu)造的執(zhí)行(當(dāng)然前提是它們沒有訪問靜態(tài)字段)。

不過CLR在加載一個類型時怎么知道其中包含的靜態(tài)構(gòu)造方法是編譯器加上的還是原C#代碼中顯式提供的呢?事實上這是beforefieldinit的作用。

根據(jù)上面的原則再來分析一下:OsrPINVOKE中沒有顯式聲明的靜態(tài)構(gòu)造,所以編譯器會生成一個默認(rèn)的靜態(tài)構(gòu)造并把helper的實例創(chuàng)建放入其中。而這個默認(rèn)的靜態(tài)構(gòu)造只會在helper這個唯一的靜態(tài)字段被訪問時才會執(zhí)行。而代碼中沒有任何地方訪問了helper,所以O(shè)srPINVOKE的靜態(tài)構(gòu)造根本就沒有執(zhí)行,helper根本就沒有被new出來,SWIGStringHelper的靜態(tài)構(gòu)造自然也就沒有執(zhí)行。

所以要解決這個問題的話只要在OsrPINVOKE里面顯式聲明一個靜態(tài)構(gòu)造方法,把new SWIGStringHelper();這一句放到里面,或者僅僅是顯式聲明一個靜態(tài)構(gòu)造并把它留空。然后重新編譯一下GDAL的Wrapper就可以了。

如果您也在.NET 4中調(diào)用GDAL時遇到了類似的問題,不妨試一下這種解決方法。

其實不僅是GDAL,其他由SWIG制作的托管Wrapper估計都會受到影響。

參考:飛秋官網(wǎng):http://www.freeeim.com/

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的『飞秋』在.NET 4中调用GDAL库时遇到的问题及解决方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。