add resource management via dispose method, closes #2

This commit is contained in:
Florian Förster 2025-03-21 08:58:23 +01:00
parent c8c1ea72b4
commit e049523384
3 changed files with 64 additions and 20 deletions

View File

@ -12,7 +12,8 @@ namespace dopt.SharpPython.Tests
{
base.Initialise();
}
public void TestFinalise() { base.Finalise(); }
public void TestDispose() { base.Dispose(); }
public void TestAssertNotDisposed() { base.AssertNotDisposed(); }
public int TestCall_factorial(int number)
{
@ -84,7 +85,7 @@ namespace dopt.SharpPython.Tests
public void Initialise_Finalise_Test()
{
plugin.TestInitialise();
plugin.TestFinalise();
plugin.TestDispose();
}
[TestMethod]
public void Call_Python_Test()
@ -92,7 +93,7 @@ namespace dopt.SharpPython.Tests
plugin.TestInitialise();
var fact = plugin.TestCall_factorial(3);
Assert.AreEqual(6, fact);
plugin.TestFinalise();
plugin.TestDispose();
}
[TestMethod]
public void Call_Python_EncodeDatetime()
@ -104,7 +105,7 @@ namespace dopt.SharpPython.Tests
string encoded_to_python = plugin.TestCall_EncodeDateTime(dateTime);
Assert.AreEqual(target, encoded_to_python);
plugin.TestFinalise();
plugin.TestDispose();
}
[TestMethod]
public void Call_Python_EncodeDatetimeWithTZ()
@ -116,7 +117,7 @@ namespace dopt.SharpPython.Tests
string encoded_to_python = plugin.TestCall_EncodeDateTime(dateTime);
Assert.AreEqual(target, encoded_to_python);
plugin.TestFinalise();
plugin.TestDispose();
}
[TestMethod]
public void Call_Python_DecodeDatetime()
@ -127,7 +128,7 @@ namespace dopt.SharpPython.Tests
DateTime decoded_from_python = plugin.TestCall_DecodeDateTime(dateTime);
Assert.AreEqual(dateTime, decoded_from_python);
plugin.TestFinalise();
plugin.TestDispose();
}
[TestMethod]
public void Call_Python_DecodeDatetimeWithTZ()
@ -138,7 +139,7 @@ namespace dopt.SharpPython.Tests
DateTime decoded_from_python = plugin.TestCall_DecodeDateTime(dateTime);
Assert.AreEqual(dateTime, decoded_from_python);
plugin.TestFinalise();
plugin.TestDispose();
}
[TestMethod]
public void Call_Python_PrintString()
@ -146,7 +147,21 @@ namespace dopt.SharpPython.Tests
plugin.TestInitialise();
string test = "printing from C#";
plugin.TestCall_String(test);
plugin.TestFinalise();
plugin.TestDispose();
}
[TestMethod]
public void Call_AssertNotDisposed_DisposedPlugin_Success()
{
plugin.TestInitialise();
plugin.TestAssertNotDisposed();
plugin.TestDispose();
}
[TestMethod]
public void Call_AssertNotDisposed_DisposedPlugin_Exception()
{
plugin.TestInitialise();
plugin.TestDispose();
Assert.ThrowsException<PythonCallDisposedException>(() => plugin.TestAssertNotDisposed());
}
}

View File

@ -5,6 +5,11 @@ using System.Reflection;
namespace dopt.SharpPython
{
public class PythonCallDisposedException: Exception
{
public PythonCallDisposedException() { }
public PythonCallDisposedException(string message) : base(message) { }
}
public abstract class BasePlugin
{
protected const string relPathToPyDll = @".\python\python311.dll";
@ -14,11 +19,13 @@ namespace dopt.SharpPython
private IntPtr _threadState;
protected bool _prepared = false;
protected bool _initialised = false;
private static bool verbose_output;
protected bool _disposed = false;
private bool verbose;
public BasePlugin(bool verbose = false)
{
verbose_output = verbose;
this.verbose = verbose;
PrepareEnv();
}
@ -26,7 +33,7 @@ namespace dopt.SharpPython
{
Type t = typeof(BasePlugin);
Assembly assembly = t.Assembly;
if (verbose_output)
if (this.verbose)
{
Console.WriteLine($"Location:\n{assembly.Location}\n---\nCodeBase:\n{assembly.CodeBase}");
}
@ -37,7 +44,7 @@ namespace dopt.SharpPython
assemPath = assemPath.Replace("file:///", "");
}
string dllDir = System.IO.Path.GetDirectoryName(assemPath);
if (verbose_output)
if (verbose)
{
Console.WriteLine($"Current DLL Dir: {dllDir}");
}
@ -83,17 +90,20 @@ namespace dopt.SharpPython
protected void Initialise()
{
if (!_prepared) PrepareEnv();
if (_prepared) PrepareEnv();
PythonEngine.Initialize();
Codecs.RegisterAll(verbose_output);
Codecs.RegisterAll(verbose);
_threadState = PythonEngine.BeginAllowThreads(); // release GIL for use in other threads
_initialised = true;
}
protected void Finalise()
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool disposing)
{
PythonEngine.EndAllowThreads(_threadState);
/*
@ -105,8 +115,27 @@ namespace dopt.SharpPython
AppContext.SetSwitch("System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization", true);
PythonEngine.Shutdown();
AppContext.SetSwitch("System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization", false);
_initialised = false;
if (disposing)
{
_initialised = false;
_disposed = true;
}
}
protected void AssertNotDisposed()
{
if ( _disposed )
{
string message = @"It was tried to operate on a disposed
instance of the plugin, which is not supported.
A new instance must be instatiated.";
message = message.Replace("\n", "").Replace("\t", "");
throw new PythonCallDisposedException(message);
}
}
~BasePlugin()
{
Dispose(false);
}
}
}

View File

@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
<Version>0.2.1</Version>
<Version>0.3.0</Version>
<Company>d-opt GmbH</Company>
<Authors>d-opt GmbH</Authors>
</PropertyGroup>