2011-08-31 51 views
21

我明白爲什麼System.Data.SQLite.dll在32位和64位版本中提供。所以我們不要詳談,繼續前進。 :)在32位和64位C#世界中使用System.Data.SQLite的選項

由於這樣做,它似乎使純C#開發有點難度,有3個選擇。

  1. 是隻支持32位和力有管理 組裝編譯的x86和當你是一個64位 的失去優勢,在32或64 位運行對付的是,有環境。

  2. 是強制64位,只支持64位,失去了在32位上運行的能力,但獲得了64位的所有優點。

  3. 是創建自己的組件的兩個版本,一個 編譯x86和採用32位的SQLite,另一個編譯64 並使用64位的SQLite。它可以防止使用「ANY」作爲編譯選項 並且能夠輕鬆地將單個構建部署到任一類型。其 從發展的角度來看不是太可怕,因爲我們 將需要兩個項目。只有C#代碼正式在一個, 和另一個將只使用「鏈接」的代碼在另一個。此 僅用於編譯目的。仍然讓我們不得不爲 管理兩個輸出用於部署。

說了這麼多,我只是在尋找確認,以上是唯一正確的選擇。

如果還有其他選擇,我俯瞰請讓我知道。特別是如果有辦法獲得一個可編譯爲ANY的單個C#DLL,那麼它可以利用32位或64位,這取決於它運行的位置並仍然使用System.Data.SQLite.dll。

+0

似乎到目前爲止,已經確認沒有任何ONE DLL選項可以支持任何CPU平臺目標解決方案,並且SQLite作爲依賴項。 –

+0

你應該從nuget安裝它。請參考[本答案] [1]。 [1]:http://stackoverflow.com/a/19623876/2550529 – SepehrM

+0

的NuGet並不能真正解決手頭的問題,從2011年8月,其已經回答了這個非常非常老問題。此外,NuGet在所有開發商店都不是一種可能性,即使它是問題的最佳解決方案,也不總是一種選擇。多年來,我已經發展成爲一個更好的解決方案,它允許包裝程序集是任何CPU,並在運行時動態地正確支持32位和64位SQLite風格。然而,這是一箇舊的封閉問題,所以人們應該快速轉向Q&A,因爲軟件老化很快。 –

回答

14

有在AnyCPU保持你的主要應用2個共同的解決辦法:

  • 同時安裝在x86和x64的程序集到GAC:他們可以(!應該)具有相同的組件名稱和GAC將自動決定是使用x86還是x64版本。

  • 鉤入AppDomain.AssemblyResolve和使用Assembly.LoadFrom

+0

你可以從nuget安裝它。參考:http:// stackoverflow。com/questions/19623823/sqlite -with-vs2012-and-net-4-5-any-cpu-build/19623876#19623876 – SepehrM

3

從發展的角度來看,它並不是很可怕,因爲我們需要兩個項目。

這不是真的 - 你可以在同一個項目中使用兩個構建配置。在部署時,您需要構建x86和x64,但代碼庫和項目可以相同。

我目前在一個較大的生產項目中執行此操作,這些都歸因於SQLite,但也包括其他包含x64和x86變體的本機/互操作庫。

+0

這與我剛剛手動黑客入侵項目文件所做的內容基本相同。你仍然最終得到兩個受管DLL的32位和64位。 –

+0

這只是選項3的變體,具有相同的結果。該問題的目標是找到具有NEW結果的NEW選項,可以讓您獲得與SQLite相關的任何CPU平臺目標構建。 –

+3

@羅德尼:是的,這是選項3的變體 - 但它帶走了選項3的主要難題之一,因爲您不必維護兩個項目... –

2

通常情況下,選擇一種方法即可,除非您的應用程序需要超過4GB的內存。記住64位操作系統上的32位應用程序具有64位的絕大多數優點,而沒有許多缺點。這就是爲什麼x86是VS 2010中.exe應用程序的默認目標。

+1

正確,並且不僅僅是記憶的優勢,但那是最引人注目的一個。有一些問題可以從一個32位的世界訪問操作系統的64位區域,如果你活着的話,你必須知道如何操作,在這種情況下你通常不用擔心任何構建這些額外的東西。 –

6

Oracle的ODP.NET相對於本機32/64位OCI DLL存在類似的問題。

我們已經通過手工裝箱兩個「86」和「64」平臺,爲我們的項目,然後編輯我們的項目文件中使用條件引用解決它:

<Choose> 
<When Condition="'$(Platform)' == 'x64'"> 
    <ItemGroup> 
    <Reference Include="Oracle.DataAccess, processorArchitecture=x64"> 
     <SpecificVersion>False</SpecificVersion> 
     <HintPath>..\ThirdParty\ODP.NET\x64\Oracle.DataAccess.dll</HintPath> 
    </Reference> 
    <Content Include="..\ThirdParty\ODP.NET\x64\oci.dll"> 
     <Link>oci.dll</Link> 
     <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> 
    </Content> 
    <Content Include="..\ThirdParty\ODP.NET\x64\orannzsbb11.dll"> 
     <Link>orannzsbb11.dll</Link> 
     <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> 
    </Content> 
    <Content Include="..\ThirdParty\ODP.NET\x64\oraociei11.dll"> 
     <Link>oraociei11.dll</Link> 
     <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> 
    </Content> 
    <Content Include="..\ThirdParty\ODP.NET\x64\OraOps11w.dll"> 
     <Link>OraOps11w.dll</Link> 
     <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> 
    </Content> 
    </ItemGroup> 
</When> 
<When Condition="'$(Platform)' == 'x86'"> 
    <ItemGroup> 
    <Reference Include="Oracle.DataAccess, processorArchitecture=x86"> 
     <SpecificVersion>False</SpecificVersion> 
     <HintPath>..\ThirdParty\ODP.NET\x86\Oracle.DataAccess.dll</HintPath> 
    </Reference> 
    <Content Include="..\ThirdParty\ODP.NET\x86\oci.dll"> 
     <Link>oci.dll</Link> 
     <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> 
    </Content> 
    <Content Include="..\ThirdParty\ODP.NET\x86\orannzsbb11.dll"> 
     <Link>orannzsbb11.dll</Link> 
     <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> 
    </Content> 
    <Content Include="..\ThirdParty\ODP.NET\x86\oraociei11.dll"> 
     <Link>oraociei11.dll</Link> 
     <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> 
    </Content> 
    <Content Include="..\ThirdParty\ODP.NET\x86\OraOps11w.dll"> 
     <Link>OraOps11w.dll</Link> 
     <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> 
    </Content> 
    </ItemGroup> 
</When> 
</Choose> 

這使我們避免使用2個不同的項目。我相信你可以爲 SQLite做類似的事情。

+0

是的,這是一個更難以維護的解決方案,因爲手動黑客攻擊項目文件會創建隱藏的信息,並非所有的開發者都會意識到,這就是爲什麼我們選擇雙重項目來完成這項工作,文件。還有一個兩個DLL作爲輸出管理。 –

+0

這只是選項3的變體,具有相同的結果。該問題的目標是找到具有NEW結果的NEW選項,可以讓您獲得與SQLite相關的任何CPU平臺目標構建。 –

+4

@Rodney這個解決方案的目標是避免2個項目,在這個意義上說它是「新」。我從未聲稱它將能夠實現「任何CPU」。順便說一句,這不是真的「黑客」 - 這是記錄良好的MSBuild語法。如果你的項目是項目層次的根源,那麼有2個項目可能是一個更清潔的解決方案。但是,如果它處於10個左右的依賴關係之下(就像我們的情況那樣),那麼我認爲避免必須重複所有的依賴關係是非常值得的。 –

21

服務從子目錄右組件這是從Springy76答案的闡述。這樣做:

public class AssemblyResolver 
{ 
    public static void HandleUnresovledAssemblies() 
    { 
     AppDomain currentDomain = AppDomain.CurrentDomain; 
     currentDomain.AssemblyResolve += currentDomain_AssemblyResolve; 
    } 

    private static Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args) 
    { 
     if (args.Name == "System.Data.SQLite") 
     { 
      var path = Path.Combine(pathToWhereYourNativeFolderLives, "Native"); 

      if (IntPtr.Size == 8) // or for .NET4 use Environment.Is64BitProcess 
      { 
       path = Path.Combine(path, "64"); 
      } 
      else 
      { 
       path = Path.Combine(path, "32"); 
      } 

      path = Path.Combine(path, "System.Data.SQLite.DLL"); 

      Assembly assembly = Assembly.LoadFrom(path); 
      return assembly; 
     } 

     return null; 
    } 
} 

確保產生點無論是針對32位或64位的SQLite的Dll的正確位置的路徑。我個人在這個NuGet包中獲得了很好的結果:http://www.nuget.org/packages/SQLitex64

(你只需要使用NuGet包來獲得已編譯的SQLite Dll,一旦你有了它們,你的項目由NuGet和NuGet包自己創建,事實上,離開參考可能會干擾這個解決方案,因爲SQLite永遠不會被認爲是一個未解決的程序集。)

儘可能早地調用'HandleUnresolvedAssemblies()',最好在任何Bootstrapping期間。

+0

但隨着對dll的引用被刪除,代碼無法找到名稱空間和方法這個類,並且不能編譯。你如何解決這個問題? – DefenestrationDay

+0

此解決方案適用於您正在使用其他庫來處理與SQLite通信工作的情況。在SQLite中使用nHibernate就是一個例子。 如果您想直接訪問類方法,那麼您需要查看另一個解決方案,例如發佈在另一個答案中的條件構建技巧。 – Holf

1

您也可以通過在Visual Studio中改變編譯選項解決此問題:

在Visual Studio中更改編譯設置:

  1. 轉到你的程序的啓動項目。
  2. 打開屬性窗口。
  3. 單擊編譯選項卡。
  4. 點擊高級編譯選項。
  5. 將目標CPU選項更改爲x86。

即使在64位計算機上運行,​​程序現在也會始終以32位模式運行。

您還可以提供兩種發行版,每種發行版都有一個發行版,如上所述。雖然這將成爲未來的標準,但對於我目前的項目來說,這是最好和最簡單的選擇。

2

Branko Dimitrijevic說:「我相信你可以爲SQLite做類似的事情。」這是正確的。 :)

有同樣的問題,我發現羅德尼的問題和Branko的答案,並嘗試自己。對於任何人誰希望看到我工作的SQLite實現,在這裏你去:

<Choose> 
    <When Condition="'$(Platform)' == 'x64'"> 
    <ItemGroup> 
     <Reference Include="System.Data.SQLite, Version=1.0.88.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=AMD64"> 
     <SpecificVersion>False</SpecificVersion> 
     <HintPath>System.Data.SQLite\x64\System.Data.SQLite.dll</HintPath> 
     </Reference> 
    </ItemGroup> 
    </When> 
    <When Condition="'$(Platform)' == 'x86'"> 
    <ItemGroup> 
     <Reference Include="System.Data.SQLite, Version=1.0.88.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=AMD64"> 
     <SpecificVersion>False</SpecificVersion> 
     <HintPath>System.Data.SQLite\x86\System.Data.SQLite.dll</HintPath> 
     </Reference> 
    </ItemGroup> 
    </When> 
</Choose> 

<ItemGroup> 
    <Reference Include="Microsoft.CSharp" /> 
    <Reference Include="System" /> 
    <Reference Include="System.configuration" /> 
    <Reference Include="System.Core" /> 
    <Reference Include="System.Windows.Forms" /> 
    <Reference Include="System.Xml.Linq" /> 
    <Reference Include="System.Data.DataSetExtensions" /> 
    <Reference Include="System.Data" /> 
    <Reference Include="System.Xml" /> 
</ItemGroup> 

當然,你可以命名HintPath任何你喜歡。

我發現這是一個完美的解決方案:我可以維護一個項目,並根據需要快速在目標平臺之間切換。唯一潛在的缺點是我無法在解決方案資源管理器中看到參考。但是這對於整體功能來說是一個小的代價。