IServiceDisposable
Assigning to IServiceDisposable makes it easier to dispose service. Note, dispose is not needed when service doesn't have a cache.
// Create service with builder
using IServiceDisposable service = new ServiceBuilder()
.Defaults()
.AddHandlers(new ServiceHandlers())
.Build();
IServiceDisposable
/// <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 { }
Cache and Entry Policy
Cache policy (IRequestPolicy<CachePolicy>) determines which request types are cached.
Entry policy (IRequestPolicy<EntryPolicy>) determines whether cache entry is disposed and reference nulled.
// Choose cache policy (Yes)
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
using IServiceDisposable service = Services.Create(semaphoreFactory, cachePolicy, default, entryPolicy);
If no policy is provided, service does not use cache and doesn't need dispose.
// Create service without cache
IService service = Services.Create(ServiceHandlers.Instance, cachePolicy: null);
Service needs disposing if it carries any result type that needs disposing.
// Named semaphore factory
Action<IQuery<string, Semaphore>> semaphoreFactory = q => q.Response.SetValue(new Semaphore(0, 1));
// Choose cache policy (Yes)
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 semaphores which must be disposed
Semaphore s1 = service.GetRequired("Key_1");
Semaphore s2 = service.GetRequired("Key_2");
// Get semaphore reference for "Key_1" again.
Semaphore s1again = service.GetRequired("Key_1");
// Test if we get same reference
Console.WriteLine(s1.Equals(s1again));
// Dispose service and all its cached semaphores
service.Dispose();
If no result type needs dispose, then service doesn't either.
// 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
Console.WriteLine(Object.ReferenceEquals(s1, s2));
// Append suffix
Console.WriteLine(s1);
Dispose Attachables
IDisposable objects can be attached to service 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();
Dispose actions can also be attached to be invoked 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
Dispose belating handles can taken from service. Service's dispose is not carried out until service itself and all belate handles are disposed.
// 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;
public class service_dispose
{
public static void Run()
{
// IServiceDisposable
{
// <1>
// Create service with builder
using IServiceDisposable service = new ServiceBuilder()
.Defaults()
.AddHandlers(new ServiceHandlers())
.Build();
// </1>
}
{
// Named semaphore factory
Action<IQuery<string, Semaphore>> semaphoreFactory = q => q.Response.SetValue(new Semaphore(0, 1));
// <11>
// Choose cache policy (Yes)
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
using IServiceDisposable service = Services.Create(semaphoreFactory, cachePolicy, default, entryPolicy);
// </11>
}
{
// <12>
// Named semaphore factory
Action<IQuery<string, Semaphore>> semaphoreFactory = q => q.Response.SetValue(new Semaphore(0, 1));
// Choose cache policy (Yes)
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 semaphores which must be disposed
Semaphore s1 = service.GetRequired("Key_1");
Semaphore s2 = service.GetRequired("Key_2");
// Get semaphore reference for "Key_1" again.
Semaphore s1again = service.GetRequired("Key_1");
// Test if we get same reference
Console.WriteLine(s1.Equals(s1again));
// 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
Console.WriteLine(Object.ReferenceEquals(s1, s2));
// Append suffix
Console.WriteLine(s1);
// </14>
}
// Dispose Attachable
{
// <15>
// 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();
// </15>
}
// Dispose Action
{
// <15B>
// 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();
// </15B>
}
// Belated Dispose
{
// <16>
// 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();
// </16>
}
}
}