[英]System.AccessViolationException in C# interface to Swi-prolog
我是新來的,我希望我能找到解決我問題的方法。 問題的背景如下:
SwiPlCs.dll
(一個 CSharp 類庫,用於將 .NET 語言與 Swi-Prolog 連接起來)方法#1:
public void LaunchAssessment()
{
Dictionary<string, string> questions = new Dictionary<string, string>();
#region : Querying prolog using SwiPlCs
try
{
if (!PlEngine.IsInitialized)
{
String[] param = { "-q" };
PlEngine.Initialize(param);
PlQuery.PlCall("consult('D:/My FYP Work/initialAssessment')");
using (var q = new PlQuery("go(X, Y)"))
{
foreach (PlQueryVariables v in q.SolutionVariables)
{
questions.Add("name", v["X"].ToString());
questions.Add("age", v["Y"].ToString());
}
}
}
}
catch (SbsSW.SwiPlCs.Exceptions.PlException exp)
{
throw new FaultException<PrologFault>(new PrologFault(exp.Source), exp.MessagePl);
}
#endregion
Callback.PoseQuestion(questions, ResponseType.None);
}
方法#2:
public void DetermineAgeGroup(int age)
{
//Determine age group
string age_group = string.Empty;
try
{
using (var query = new PlQuery("age_group(" + age + ", G)"))
{
foreach (PlQueryVariables v in query.SolutionVariables)
age_group += v["G"].ToString();
}
}
catch (SbsSW.SwiPlCs.Exceptions.PlException exp)
{
throw new FaultException<PrologFault>(new PrologFault(exp.Source), exp.MessagePl);
}
//Check whether age_group is found or not
if (string.IsNullOrEmpty(age_group))
{
throw new FaultException<NoSolutionFoundFault>(new NoSolutionFoundFault("No solution found"), "Age specified exceeds the diagnosis range!");
}
else
{
Callback.RespondToUser(age_group, ResponseType.Age);
}
}
方法#3:
public void QuitProlog()
{
if (PlEngine.IsInitialized)
{
PlEngine.PlCleanup();
}
}
客戶端調用第一個方法就好了,並且成功返回了第一個查詢的結果。 當客戶端嘗試調用第二個方法時,會拋出異常並帶有消息(嘗試讀取或寫入受保護的內存),導致應用程序凍結。 我檢查了事件查看器,這就是我得到的:
Application: w3wp.exe
Framework Version: v4.0.30319
Description: The process was terminated due to an unhandled exception.
Exception Info: System.AccessViolationException
堆:
at SbsSW.SwiPlCs.SafeNativeMethods.PL_new_term_ref()
at SbsSW.SwiPlCs.PlQuery..ctor(System.String, System.String)
at SbsSW.SwiPlCs.PlQuery..ctor(System.String)
at PrologQueryService.PrologQueryService.DetermineAgeGroup(Int32)
我還嘗試將接口用於 .NET 項目。
在查看 SWI-Prolog 的 CSharp 接口的官方存儲庫中,我注意到該項目很舊,並且官方網站的下載頁面中提供的二進制文件中似乎沒有包含最新的更新。
然后我做了以下步驟:
專用於 .NET 的 contrib 存儲庫表明兼容的 SWI-Prolog 版本(在撰寫本文時)為“8.0.3-1”(查看自述文件)。 -> 然后我從我的計算機上卸載了最新的穩定版並安裝了指定的穩定版。 我是從這個鏈接上舊版本的完整下載列表中得到的。
我克隆了SWI-Prolog/contrib-swiplcs存儲庫,從解決方案中卸載了不兼容的項目,就我而言,因為我不使用 Visual Studio。 -> 我將目標框架設置為 Net Framework 4.8 並重新編譯它(您也可以使用標准 NET 執行此操作)。 注意舊項目文件中定義的一些 pragma 指令(例如,我通過代碼重新定義了_PL_X64變量。
我將主要的單元測試方法帶入了一個帶有 xUnit 的新項目,並進行了適當的更改。
我將目標設置為 x64,重新編譯並重新構建測試和“hello world”示例。
有效! 我能夠將 SWI-Prolog 用於 Net 4.8 和其他 Net Core 應用程序(如果您進行了必要的更改以針對 Net Standard)。 在這兩種情況下你都不應該有任何問題)。
這是我的fork作為初步示例。
最后,我可以在我的 C# 應用程序中加載一個帶有程序的 *.pl Prolog 文件,並使用它來評估一些業務邏輯規則(帶有布爾答案 [Permitted/Not-Permitted] 的示例):
[Fact]
public void ShouldLoadAProgramAndUseIt()
{
var pathValues = Environment.GetEnvironmentVariable("PATH");
pathValues += @";C:\Program Files\swipl\bin";
Environment.SetEnvironmentVariable("PATH", pathValues);
// Positioning to project folder
var currentDirectory = Directory.GetCurrentDirectory().Split('\\').ToList();
currentDirectory.RemoveAll(r => currentDirectory.ToArray().Reverse().Take(3).Contains(r));
var basePath = currentDirectory.Aggregate((c1, c2) => $"{c1}\\{c2}");
var filePath = $"{basePath}\\prolog_examples\\exec_checker.pl";
String[] param = { "-q", "-f", filePath };
PlEngine.Initialize(param);
try
{
var query = "exutable('2020-08-15',[('monthly', ['2019-12-30', '2020-03-10'])])";
_testOutputHelper.WriteLine($"Query: {query}");
using (var q = new PlQuery(query))
{
var booleanAnswer = q.NextSolution();
_testOutputHelper.WriteLine($"Answer: {booleanAnswer}");
Assert.True(booleanAnswer);
}
query = "exutable('2020-08-15',[('daily', ['2019-12-30', '2020-08-15'])])";
_testOutputHelper.WriteLine($"Query: {query}");
using (var q = new PlQuery(query))
{
var booleanAnswer = q.NextSolution();
_testOutputHelper.WriteLine($"Answer: {booleanAnswer}");
Assert.False(booleanAnswer);
}
}
finally
{
PlEngine.PlCleanup();
}
}
嘗試在第一種方法結束時關閉引擎並在第二種方法中再次初始化它。
除非您反對,否則您可以將此作為問題的答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.