IServiceDisposable
IServiceDisposable and IServiceDisposable<Request,Response> expose IDisposable.
/// <summary>Disposable service</summary>
/// <remarks>Compound of two interfaces is used in methods that need to indicate on return type both properties.</remarks>
public interface IServiceDisposable : IService, IDisposable { }
/// <summary>Disposable service</summary>
/// <remarks>Compound of two interfaces is used in methods that need to indicate on return type both properties.</remarks>
public interface IServiceDisposableT : IServiceT, IDisposable { }
/// <summary>Disposable service</summary>
/// <remarks>Compound of two interfaces is used in methods that need to indicate on return type both properties.</remarks>
public interface IServiceDisposable<Request> : IService<Request>, IDisposable where Request : notnull { }
/// <summary>Disposable service</summary>
/// <remarks>Compound of two interfaces is used in methods that need to indicate on return type both properties.</remarks>
public interface IServiceOfDisposable<Response> : IServiceOf<Response>, IDisposable { }
/// <summary>Disposable service</summary>
/// <remarks>Compound of two interfaces is used in methods that need to indicate on return type both properties.</remarks>
public interface IServiceDisposable<Request, Response> : IService<Request, Response>, IDisposable where Request : notnull { }
Services.Create() creates a IServiceDisposable. The using statement invokes .Dispose() at closing of block { }.
using IServiceDisposable service = Services.Create(ServiceHandlers.Instance);
Services.Create<>() constructs a IServiceDisposable<>.
using IServiceDisposable<object,object> service = Services.Create<object, object>(ServiceHandlers.Instance);
Cache and Entry Policy
EntryPolicy determines whether cached entries are disposed and whether reference is nulled.
// Named semaphore factory
Action<IQuery<string, Semaphore>> semaphoreFactory = q => q.Response.SetValue(new Semaphore(0, 1));
// Create service with cache and dispose policy
IServiceDisposable<string, Semaphore> service = Services.Create<string, Semaphore>(semaphoreFactory, CachePolicies.DefaultYes, default, EntryPolicies.DisposeAndNull);
// Create named semaphore
Semaphore semaphoreA = service.GetRequired("A");
// Dipose service and cached semaphores.
service.Dispose();
// throws ObjectDisposeException
semaphoreA.WaitOne();
If no policy is provided, service doesn't cache any result and won't need dispose.
// Create service without cache
IService service = Services.Create(ServiceHandlers.Instance, cachePolicy: null);
Cached results that implement IDisposable are disposed along with service, if dispose flag is attached to entry.
// Named semaphore factory
Action<IQuery<string, Semaphore>> semaphoreFactory = q => q.Response.SetValue(new Semaphore(0, 1));
// Choose cache policy (Yes to all requests)
IRequestPolicy<CachePolicy> cachePolicy = CachePolicies.DefaultYes;
// Choose entry policy: Cached entries are disposed and nulled with service
IRequestPolicy<EntryPolicy> entryPolicy = EntryPolicies.DisposeAndNull;
// Create service with cache
IServiceDisposable<string, Semaphore> service = Services.Create<string, Semaphore>(semaphoreFactory, cachePolicy, default, entryPolicy);
// Get-or-create named semaphores
Semaphore semaphoreA = service.GetRequired("A");
Semaphore semaphoreB = service.GetRequired("B");
// Get semaphore "A"
Semaphore semaphoreAagain = service.GetRequired("A");
// Test if we get same reference
WriteLine( semaphoreA.Equals(semaphoreAagain) ); // "True"
// Dispose service and all its cached semaphores
service.Dispose();
If no result type needs dispose, then service doesn't either, and can be left to be garbage collected.
// Handler
Action<IQuery<string, string>> suffixAppender = q => q.Response.SetValue(q.Request + "-SUFFIX");
// Create service with cache
IServiceDisposable<string, string> service = Services.Create<string, string>(suffixAppender, CachePolicies.DefaultYes, default, EntryPolicies.DisposeAndNull);
// Get string
string s1 = service.GetRequired("Hello");
// Get same cached string
string s2 = service.GetRequired("Hello");
// Test if cached, test if references are same
WriteLine(Object.ReferenceEquals(s1, s2));
// Append suffix
WriteLine(s1);
Dispose Attachables
.AttachDisposable(disposable) attaches an object to be disposed along with service.
// Create a lock which must be disposed
ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
// Handler
Action<IQuery<string, string>> suffixAppender = q =>
{
_lock.EnterWriteLock();
q.Response.SetValue(q.Request + "-SUFFIX");
_lock.ExitWriteLock();
};
// Create service with cache
IServiceDisposable<string, string> service = Services.Create<string, string>(suffixAppender, CachePolicies.DefaultYes, default, EntryPolicies.DisposeAndNull);
// Attach lock for dispose
(service as IDisposeAttachable)!.AttachDisposable(_lock);
// Query
string text = service.GetRequired("Hello");
// Dispose service and lock
service.Dispose();
.AttachDisposeAction(func, state) attaches a delegate to be executed at dispose.
// Create service with cache
IServiceDisposable service = Services.Create(ServiceHandlers.Instance, CachePolicies.DefaultYes);
// Create dispose action
Action<object> action = state => Console.WriteLine("Disposed");
// Attach lock for dispose
(service as IDisposeAttachable)!.AttachDisposeAction(action, null!);
// Dispose service
service.Dispose();
Belate Dispose
.BelateDispose() creates a handle that post-pones dispose. Dispose is carried out when service itself and all belate handles are disposed. This is typically used for passing ownership to other thread(s).
// Create service with cache
IServiceDisposable<string, string> service = Services.Create<string, string>(ServiceHandlers.Instance, CachePolicies.Default);
// Create belate handle
IDisposable belateHandle = (service as IDisposeBelatable)!.BelateDispose();
// Dispose service (not carried out yet)
service.Dispose();
// Dispose belate handle (carries out dispose)
belateHandle.Dispose();
Full Example
Full example
using System;
using System.Threading;
using Avalanche.Service;
using Avalanche.Utilities;
using static System.Console;
public class service_dispose
{
public static void Run()
{
{
// <01>
using IServiceDisposable service = Services.Create(ServiceHandlers.Instance);
// </01>
}
{
// <02>
using IServiceDisposable<object,object> service = Services.Create<object, object>(ServiceHandlers.Instance);
// </02>
}
try
{
// <11>
// Named semaphore factory
Action<IQuery<string, Semaphore>> semaphoreFactory = q => q.Response.SetValue(new Semaphore(0, 1));
// Create service with cache and dispose policy
IServiceDisposable<string, Semaphore> service = Services.Create<string, Semaphore>(semaphoreFactory, CachePolicies.DefaultYes, default, EntryPolicies.DisposeAndNull);
// Create named semaphore
Semaphore semaphoreA = service.GetRequired("A");
// Dipose service and cached semaphores.
service.Dispose();
// throws ObjectDisposeException
semaphoreA.WaitOne();
// </11>
}
catch (ObjectDisposedException) { }
{
// <12>
// Named semaphore factory
Action<IQuery<string, Semaphore>> semaphoreFactory = q => q.Response.SetValue(new Semaphore(0, 1));
// Choose cache policy (Yes to all requests)
IRequestPolicy<CachePolicy> cachePolicy = CachePolicies.DefaultYes;
// Choose entry policy: Cached entries are disposed and nulled with service
IRequestPolicy<EntryPolicy> entryPolicy = EntryPolicies.DisposeAndNull;
// Create service with cache
IServiceDisposable<string, Semaphore> service = Services.Create<string, Semaphore>(semaphoreFactory, cachePolicy, default, entryPolicy);
// Get-or-create named semaphores
Semaphore semaphoreA = service.GetRequired("A");
Semaphore semaphoreB = service.GetRequired("B");
// Get semaphore "A"
Semaphore semaphoreAagain = service.GetRequired("A");
// Test if we get same reference
WriteLine( semaphoreA.Equals(semaphoreAagain) ); // "True"
// Dispose service and all its cached semaphores
service.Dispose();
// </12>
}
{
// <13>
// Create service without cache
IService service = Services.Create(ServiceHandlers.Instance, cachePolicy: null);
// </13>
}
{
// <14>
// Handler
Action<IQuery<string, string>> suffixAppender = q => q.Response.SetValue(q.Request + "-SUFFIX");
// Create service with cache
IServiceDisposable<string, string> service = Services.Create<string, string>(suffixAppender, CachePolicies.DefaultYes, default, EntryPolicies.DisposeAndNull);
// Get string
string s1 = service.GetRequired("Hello");
// Get same cached string
string s2 = service.GetRequired("Hello");
// Test if cached, test if references are same
WriteLine(Object.ReferenceEquals(s1, s2));
// Append suffix
WriteLine(s1);
// </14>
}
// Dispose Attachable
{
// <21>
// Create a lock which must be disposed
ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
// Handler
Action<IQuery<string, string>> suffixAppender = q =>
{
_lock.EnterWriteLock();
q.Response.SetValue(q.Request + "-SUFFIX");
_lock.ExitWriteLock();
};
// Create service with cache
IServiceDisposable<string, string> service = Services.Create<string, string>(suffixAppender, CachePolicies.DefaultYes, default, EntryPolicies.DisposeAndNull);
// Attach lock for dispose
(service as IDisposeAttachable)!.AttachDisposable(_lock);
// Query
string text = service.GetRequired("Hello");
// Dispose service and lock
service.Dispose();
// </21>
}
// Dispose Action
{
// <22>
// Create service with cache
IServiceDisposable service = Services.Create(ServiceHandlers.Instance, CachePolicies.DefaultYes);
// Create dispose action
Action<object> action = state => Console.WriteLine("Disposed");
// Attach lock for dispose
(service as IDisposeAttachable)!.AttachDisposeAction(action, null!);
// Dispose service
service.Dispose();
// </22>
}
// Belated Dispose
{
// <31>
// Create service with cache
IServiceDisposable<string, string> service = Services.Create<string, string>(ServiceHandlers.Instance, CachePolicies.Default);
// Create belate handle
IDisposable belateHandle = (service as IDisposeBelatable)!.BelateDispose();
// Dispose service (not carried out yet)
service.Dispose();
// Dispose belate handle (carries out dispose)
belateHandle.Dispose();
// </31>
}
}
}