mirror of
https://github.com/wagesj45/CapyKit.git
synced 2024-12-21 04:42:29 -06:00
Migrating Code
This commit is contained in:
parent
1fbc49884c
commit
cbbe897d15
9 changed files with 674 additions and 0 deletions
4
CapyKit/.editorconfig
Normal file
4
CapyKit/.editorconfig
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[*.cs]
|
||||||
|
|
||||||
|
# CS8625: Cannot convert null literal to non-nullable reference type.
|
||||||
|
dotnet_diagnostic.CS8625.severity = none
|
43
CapyKit/Attributes/EnumerationAttribute.cs
Normal file
43
CapyKit/Attributes/EnumerationAttribute.cs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CapyKit.Attributes
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Custom attribute class for decorating enumeration fields with additional data.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">
|
||||||
|
/// Generic type parameter allowing for arbitrary declarations and assignments of meaning.
|
||||||
|
/// </typeparam>
|
||||||
|
[AttributeUsage(AttributeTargets.Field)]
|
||||||
|
public abstract class EnumerationAttribute<T> : Attribute
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="EnumerationAttribute{T}"/> class with a
|
||||||
|
/// specified value.
|
||||||
|
/// </summary>
|
||||||
|
/// <value> The value. </value>
|
||||||
|
public T Value { get; private set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary> Gets the value of the enumeration represented by this attribute. </summary>
|
||||||
|
/// <param name="value">
|
||||||
|
/// Initializes a new instance of the <see cref="EnumerationAttribute{T}"/> class with a
|
||||||
|
/// specified value.
|
||||||
|
/// </param>
|
||||||
|
protected EnumerationAttribute(T value)
|
||||||
|
{
|
||||||
|
this.Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
25
CapyKit/Attributes/EnumerationDescriptionAttribute.cs
Normal file
25
CapyKit/Attributes/EnumerationDescriptionAttribute.cs
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CapyKit.Attributes
|
||||||
|
{
|
||||||
|
/// <summary> An attribute class for decorating enumeration fields with a description. </summary>
|
||||||
|
/// <seealso cref="EnumerationAttribute{T}"/>
|
||||||
|
[AttributeUsage(AttributeTargets.Field)]
|
||||||
|
public class EnumerationDescriptionAttribute : EnumerationAttribute<string>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="EnumerationDescriptionAttribute"/> class with
|
||||||
|
/// the specified description.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="description"> The description of the enumeration value. </param>
|
||||||
|
public EnumerationDescriptionAttribute(string description)
|
||||||
|
: base(description)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
173
CapyKit/CapyEvent.cs
Normal file
173
CapyKit/CapyEvent.cs
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CapyKit.Extensions;
|
||||||
|
|
||||||
|
namespace CapyKit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The CapyEventReporter class is responsible for managing event subscriptions and emissions within CapyKit.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Because consumers of CapyKit may have varied ways of handling logging, the <see cref="CapyEventReporter"/> provides
|
||||||
|
/// a way for subscribers to recieve events for various "events" within the library. These can be thought of as
|
||||||
|
/// a logging solution for CapyKit.
|
||||||
|
/// </remarks>
|
||||||
|
public static class CapyEventReporter
|
||||||
|
{
|
||||||
|
#region Members
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A dictionary storing event handlers and their corresponding origins for each subscription level.
|
||||||
|
/// </summary>
|
||||||
|
private static Dictionary<EventLevel, List<(CapyEventHandler Handler, string origin)>> subscribers = new Dictionary<EventLevel, List<(CapyEventHandler Handler, string origin)>>();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subscribes the specified event handler to the event with the given subscription level and
|
||||||
|
/// origin.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// If there is no existing list for the given subscription level, a new list is created and
|
||||||
|
/// added to the dictionary.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="callback"> The event handler to subscribe. </param>
|
||||||
|
/// <param name="subscriptionLevel"> The severity level of the event to subscribe to. </param>
|
||||||
|
/// <param name="origin">
|
||||||
|
/// (Optional) The name of the method or class where the subscription is made.
|
||||||
|
/// </param>
|
||||||
|
public static void Subscribe(CapyEventHandler callback, EventLevel subscriptionLevel, [CallerMemberName] string origin = null)
|
||||||
|
{
|
||||||
|
if (!subscribers[subscriptionLevel].Any())
|
||||||
|
{
|
||||||
|
subscribers.Add(subscriptionLevel, new List<(CapyEventHandler Handler, string origin)>());
|
||||||
|
}
|
||||||
|
|
||||||
|
subscribers[subscriptionLevel].Add((callback, origin ?? "[Unknown]"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unsubscribes the specified event handler from the event with the given origin.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="callback"> The event handler to unsubscribe. </param>
|
||||||
|
/// <param name="origin">
|
||||||
|
/// The name of the method or class where the subscription was made.
|
||||||
|
/// </param>
|
||||||
|
public static void Unsubscribe(CapyEventHandler callback, string origin)
|
||||||
|
{
|
||||||
|
foreach (var value in Enum.GetValues(typeof(EventLevel)))
|
||||||
|
{
|
||||||
|
if (value is EventLevel)
|
||||||
|
{
|
||||||
|
subscribers[(EventLevel)value].RemoveAll(c => c.Handler == callback && c.origin == origin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Emits an event with the given severity level, message, and method name. </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// In order to allow for efficient calling member access via <see cref="CallerMemberNameAttribute"/>
|
||||||
|
/// , it is suggested that <paramref name="args"/> is defined explicitly for formatted messages.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="eventLevel"> The severity level of the event. </param>
|
||||||
|
/// <param name="message"> The message describing the reason for the event. </param>
|
||||||
|
/// <param name="method">
|
||||||
|
/// (Optional) The name of the method where the event was raised. String formatting for <paramref name="args"/>
|
||||||
|
/// is accepted.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="args">
|
||||||
|
/// A variable-length parameters list containing arguments for formatting the message.
|
||||||
|
/// </param>
|
||||||
|
/// <example>
|
||||||
|
/// CapyEventReporter.EmitEvent(EventLevel.Error, "Could not find the description for {0}.",
|
||||||
|
/// args: new[] { enumeration });
|
||||||
|
/// </example>
|
||||||
|
internal static void EmitEvent(EventLevel eventLevel, string message, [CallerMemberName] string method = null, params object[] args)
|
||||||
|
{
|
||||||
|
if (!subscribers.ContainsKey(eventLevel))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var formattedMessage = string.Format(message, args);
|
||||||
|
|
||||||
|
var capyEventArgs = new CapyEventArgs(eventLevel, formattedMessage, method);
|
||||||
|
|
||||||
|
foreach (var subscriber in subscribers[eventLevel])
|
||||||
|
{
|
||||||
|
subscriber.Handler(capyEventArgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A delegate representing an event handler that accepts a <see cref="CapyEventArgs"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e">The CapyEventArgs instance containing event data.</param>
|
||||||
|
public delegate void CapyEventHandler(CapyEventArgs e);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The CapyEventArgs class represents an event argument instance with event level, message, and
|
||||||
|
/// method name information.
|
||||||
|
/// </summary>
|
||||||
|
public class CapyEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the severity level of the event.
|
||||||
|
/// </summary>
|
||||||
|
public EventLevel Level { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the message describing the reason for the event.
|
||||||
|
/// </summary>
|
||||||
|
public string Message { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the method where the event was raised.
|
||||||
|
/// </summary>
|
||||||
|
public string MethodName { get; private set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructor
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the CapyEventArgs class with the specified event level, message, and method name.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="level">The severity level of the event.</param>
|
||||||
|
/// <param name="message">A descriptive message explaining the reason for the event.</param>
|
||||||
|
/// <param name="method">The name of the method where the event was raised.</param>
|
||||||
|
public CapyEventArgs(EventLevel level, string message, string method = null)
|
||||||
|
{
|
||||||
|
this.Level = level;
|
||||||
|
this.Message = message;
|
||||||
|
this.MethodName = method ?? "[Unknown]";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary> Enumeration representing different event level severity values. </summary>
|
||||||
|
public enum EventLevel
|
||||||
|
{
|
||||||
|
/// <summary> Represents a critical error that requires immediate attention. </summary>
|
||||||
|
Critical = 0,
|
||||||
|
/// <summary> Represents an error that prevents the normal execution of the application. </summary>
|
||||||
|
Error = 1,
|
||||||
|
/// <summary> Represents informational messages that provide useful context to the consumer. </summary>
|
||||||
|
Information = 2,
|
||||||
|
/// <summary> Represents detailed messages that are typically used for debugging purposes. </summary>
|
||||||
|
Debug = 3
|
||||||
|
}
|
||||||
|
}
|
9
CapyKit/CapyKit.csproj
Normal file
9
CapyKit/CapyKit.csproj
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
30
CapyKit/CapyKit.sln
Normal file
30
CapyKit/CapyKit.sln
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.8.34408.163
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CapyKit", "CapyKit.csproj", "{D1ACE10F-CBC8-4BA8-BB85-11DB4EEE5912}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BE8D96CA-FC33-4F28-AF49-0E4AEC6D3FD9}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
.editorconfig = .editorconfig
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{D1ACE10F-CBC8-4BA8-BB85-11DB4EEE5912}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D1ACE10F-CBC8-4BA8-BB85-11DB4EEE5912}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D1ACE10F-CBC8-4BA8-BB85-11DB4EEE5912}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D1ACE10F-CBC8-4BA8-BB85-11DB4EEE5912}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {AF075174-308F-4D69-9160-C3CCE89EAD68}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
93
CapyKit/Extensions/EnumerationExtensions.cs
Normal file
93
CapyKit/Extensions/EnumerationExtensions.cs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
using CapyKit.Attributes;
|
||||||
|
using CapyKit.Helpers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CapyKit.Extensions
|
||||||
|
{
|
||||||
|
public static class EnumerationExtensions
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A <typeparamref name="T"/> extension method that parses a string into an enumeration.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"> Generic type parameter. </typeparam>
|
||||||
|
/// <param name="enumeration"> The enumeration to act on. </param>
|
||||||
|
/// <param name="value"> The value. </param>
|
||||||
|
/// <returns> A T. </returns>
|
||||||
|
public static T Parse<T>(this T enumeration, string value) where T : Enum
|
||||||
|
{
|
||||||
|
return (T)Enum.Parse(typeof(T), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A <typeparamref name="T"/> extension method that parses a string into an enumeration.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"> Generic type parameter. </typeparam>
|
||||||
|
/// <param name="enumeration"> The enumeration to act on. </param>
|
||||||
|
/// <param name="value"> The string value of the <see cref="Enum"/>. </param>
|
||||||
|
/// <param name="ignoreCase"> True to ignore case. </param>
|
||||||
|
/// <returns> A T. </returns>
|
||||||
|
public static T Parse<T>(this T enumeration, string value, bool ignoreCase) where T : Enum
|
||||||
|
{
|
||||||
|
return (T)Enum.Parse(typeof(T), value, ignoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An <see cref="Enum"/> extension method that gets an integer value representing the enumation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="enumeration"> The enumeration to act on. </param>
|
||||||
|
/// <returns> The integer value of the enumeration. </returns>
|
||||||
|
public static int GetValue(this Enum enumeration)
|
||||||
|
{
|
||||||
|
return (int)Convert.ChangeType(enumeration, TypeCode.Int32);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> An <see cref="Enum"/> extension method that gets a name. </summary>
|
||||||
|
/// <param name="enumeration"> The enumeration to act on. </param>
|
||||||
|
/// <returns> The name of the enumeration. </returns>
|
||||||
|
public static string GetName(this Enum enumeration)
|
||||||
|
{
|
||||||
|
return Enum.GetName(enumeration.GetType(), enumeration) ?? "[Unknown]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> An <see cref="Enum"/> extension method that gets a human readable name. </summary>
|
||||||
|
/// <param name="enumeration"> The enumeration to act on. </param>
|
||||||
|
/// <returns> The human readable name of the enumeration. </returns>
|
||||||
|
public static string GetPrettyName(this Enum enumeration)
|
||||||
|
{
|
||||||
|
return LanguageHelper.CamelCaseToHumanReadable(GetName(enumeration));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> An <see cref="Enum"/> extension method that gets a description. </summary>
|
||||||
|
/// <param name="enumeration"> The enumeration to act on. </param>
|
||||||
|
/// <returns>
|
||||||
|
/// The description if available, otherwise the string representation of the enumeration.
|
||||||
|
/// </returns>
|
||||||
|
public static string GetDescription(this Enum enumeration)
|
||||||
|
{
|
||||||
|
var memInfo = enumeration.GetType().GetMember(enumeration.GetName());
|
||||||
|
if (memInfo.Any())
|
||||||
|
{
|
||||||
|
var attribute = memInfo.First().GetCustomAttribute(typeof(EnumerationDescriptionAttribute)) as EnumerationDescriptionAttribute;
|
||||||
|
if (attribute == null)
|
||||||
|
{
|
||||||
|
CapyEventReporter.EmitEvent(EventLevel.Error, "Could not find the description for {0}.", args: new[] { enumeration });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return attribute.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return enumeration.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
}
|
26
CapyKit/Helpers/LanguageHelper.cs
Normal file
26
CapyKit/Helpers/LanguageHelper.cs
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CapyKit.Helpers
|
||||||
|
{
|
||||||
|
public class LanguageHelper
|
||||||
|
{
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary> Converts camel case text to human readable text. </summary>
|
||||||
|
/// <param name="value"> The value. </param>
|
||||||
|
/// <returns> A string in human readable format. </returns>
|
||||||
|
public static string CamelCaseToHumanReadable(string value)
|
||||||
|
{
|
||||||
|
var regex = new Regex(@"(?<=[A-Z])(?=[A-Z][a-z]) | (?<=[^A-Z])(?=[A-Z]) | (?<=[A-Za-z])(?=[^A-Za-z])", RegexOptions.IgnorePatternWhitespace);
|
||||||
|
|
||||||
|
return regex.Replace(value, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
271
CapyKit/Pool.cs
Normal file
271
CapyKit/Pool.cs
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||||
|
|
||||||
|
namespace CapyKit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A managed pool of resources. This class provides a thread-safe way to manage a collection of
|
||||||
|
/// objects of type <typeparamref name="T"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"> The type of objects to be managed by the pool. </typeparam>
|
||||||
|
public class Pool<T>
|
||||||
|
{
|
||||||
|
#region Members
|
||||||
|
|
||||||
|
/// <summary> The collection of pooled items. </summary>
|
||||||
|
private readonly ConcurrentBag<PoolItem<T>> poolItemCollection;
|
||||||
|
|
||||||
|
/// <summary> (Immutable) The number of items in the pool. </summary>
|
||||||
|
private readonly int poolSize;
|
||||||
|
|
||||||
|
#endregion Members
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Pool{T}"/> class with the specified pool size.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="poolSize"> The size of the pool. </param>
|
||||||
|
public Pool(int poolSize)
|
||||||
|
{
|
||||||
|
this.poolSize = poolSize;
|
||||||
|
this.poolItemCollection = new ConcurrentBag<PoolItem<T>>();
|
||||||
|
FillPoolItemCollection(poolSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Pool{T}"/> class with the specified pool size
|
||||||
|
/// and constructor selector.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="poolSize"> The size of the pool. </param>
|
||||||
|
/// <param name="constructorSelector">
|
||||||
|
/// The constructor selector used to create new instances of <typeparamref name="T"/>.
|
||||||
|
/// </param>
|
||||||
|
public Pool(int poolSize, Func<T> constructorSelector)
|
||||||
|
{
|
||||||
|
this.poolSize = poolSize;
|
||||||
|
this.poolItemCollection = new ConcurrentBag<PoolItem<T>>();
|
||||||
|
FillPoolItemCollection(poolSize, constructorSelector);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Pool{T}"/> class with the specified collection
|
||||||
|
/// of items.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="collection">
|
||||||
|
/// The collection of <typeparamref name="T"/> items with which to seed the pool.
|
||||||
|
/// </param>
|
||||||
|
public Pool(IEnumerable<T> collection)
|
||||||
|
{
|
||||||
|
this.poolSize = collection.Count();
|
||||||
|
this.poolItemCollection = new ConcurrentBag<PoolItem<T>>();
|
||||||
|
FillPoolItemCollection(collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the pool with the specified number of items using the default constructor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="poolSize"> The size of the pool. </param>
|
||||||
|
private void FillPoolItemCollection(int poolSize)
|
||||||
|
{
|
||||||
|
FillPoolItemCollection(poolSize, () => default(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes the pool with the specified number of items using the specified constructor
|
||||||
|
/// selector.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="poolSize"> The size of the pool. </param>
|
||||||
|
/// <param name="constructorSelector"> The constructor selector. </param>
|
||||||
|
private void FillPoolItemCollection(int poolSize, Func<T> constructorSelector)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < poolSize; i++)
|
||||||
|
{
|
||||||
|
this.poolItemCollection.Add(new PoolItem<T>(constructorSelector(), i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Fill the pool item collection from an existing <typeparamref name="T"/> collection. </summary>
|
||||||
|
/// <param name="collection"> The <typeparamref name="T"/> collection. </param>
|
||||||
|
private void FillPoolItemCollection(IEnumerable<T> collection)
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
foreach (var item in collection)
|
||||||
|
{
|
||||||
|
this.poolItemCollection.Add(new PoolItem<T>(item, index++));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets the first available item from the pool and sets its lock. </summary>
|
||||||
|
/// <returns> The first available item from the pool. </returns>
|
||||||
|
public PoolItem<T> GetAvailableItem()
|
||||||
|
{
|
||||||
|
lock (this.poolItemCollection)
|
||||||
|
{
|
||||||
|
if (this.poolItemCollection.Any(item => !item.Locked))
|
||||||
|
{
|
||||||
|
var firstAvailableItem = this.poolItemCollection.First(item => !item.Locked);
|
||||||
|
firstAvailableItem.SetLock();
|
||||||
|
|
||||||
|
CapyEventReporter.EmitEvent(EventLevel.Debug, "Accessed ppol and retrieved {0}", args: new[] { firstAvailableItem });
|
||||||
|
|
||||||
|
return firstAvailableItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CapyEventReporter.EmitEvent(EventLevel.Error, "Could not return an available item.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Releases the lock on the specified item and returns it to the pool. </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method sets the <see cref="PoolItem{T}.Locked"/> flag to <see langword="false"/> so that
|
||||||
|
/// it can be retrieved by <see cref="Pool{T}.GetAvailableItem"/>.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="item"> The item to release. </param>
|
||||||
|
public void ReleaseItem(PoolItem<T> item)
|
||||||
|
{
|
||||||
|
item.ReleaseLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> A pool item. This class cannot be inherited. </summary>
|
||||||
|
/// <typeparam name="T"> The type of the pooled item. </typeparam>
|
||||||
|
public sealed class PoolItem<T>
|
||||||
|
{
|
||||||
|
#region Members
|
||||||
|
|
||||||
|
/// <summary> The pooled item. </summary>
|
||||||
|
private readonly T item;
|
||||||
|
|
||||||
|
/// <summary> A flag indicating whether the item is locked or not. </summary>
|
||||||
|
private bool locked;
|
||||||
|
|
||||||
|
/// <summary> The zero-based index of the pooled item. </summary>
|
||||||
|
private readonly int index;
|
||||||
|
|
||||||
|
/// <summary> The name of the pooled item <see cref="Type"/>. </summary>
|
||||||
|
private readonly string typeName;
|
||||||
|
|
||||||
|
#endregion Members
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary> Gets the pooled resource. </summary>
|
||||||
|
/// <value> The pooled resource. </value>
|
||||||
|
public T Item
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets a value indicating whether this object is locked or not. </summary>
|
||||||
|
/// <value> A value indicating whether this object is locked or not. </value>
|
||||||
|
public bool Locked
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.locked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets the zero-based index of the pooled item. </summary>
|
||||||
|
/// <value> The index. </value>
|
||||||
|
public int Index
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Gets the name of the <see cref="Type"/> of the pooled item. </summary>
|
||||||
|
/// <value> The name of the <see cref="Type"/> of the pooled item. </value>
|
||||||
|
public string TypeName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.typeName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Properties
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="PoolItem{T}"/> class with the specified item and
|
||||||
|
/// index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item"> The pooled item. </param>
|
||||||
|
/// <param name="index"> The zero-based index of the pooled item. </param>
|
||||||
|
internal PoolItem(T item, int index)
|
||||||
|
{
|
||||||
|
this.item = item;
|
||||||
|
this.index = index;
|
||||||
|
this.locked = false;
|
||||||
|
this.typeName = typeof(T).Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Constructors
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
/// <summary> Sets the lock on the item indicating that it is in use. </summary>
|
||||||
|
/// <remarks> If the item is already locked, an error event is emitted. </remarks>
|
||||||
|
/// <returns>
|
||||||
|
/// <see langword="true"/> if the item is locked successfully, <see langword="false"/> if it
|
||||||
|
/// fails.
|
||||||
|
/// </returns>
|
||||||
|
public bool SetLock()
|
||||||
|
{
|
||||||
|
if (this.locked)
|
||||||
|
{
|
||||||
|
CapyEventReporter.EmitEvent(EventLevel.Error, "Lock requested for {0}, but the lock request failed.", args: new[] { this });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.locked = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary> Releases the lock on the item. </summary>
|
||||||
|
/// <remarks> If the item is not locked, an error event is emitted. </remarks>
|
||||||
|
public void ReleaseLock()
|
||||||
|
{
|
||||||
|
if (!this.locked)
|
||||||
|
{
|
||||||
|
CapyEventReporter.EmitEvent(EventLevel.Error, "Lock release requested for {0}, but the lock was already released.", args: new[] { this } );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.locked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Methods
|
||||||
|
|
||||||
|
#region Overrides
|
||||||
|
|
||||||
|
/// <summary> Returns a string that represents the current object and its lock state. </summary>
|
||||||
|
/// <returns> A string that represents the current object and its lock state. </returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("{0} {1} ({2})", this.typeName, this.index, this.locked ? "Locked" : "Unlocked");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Overrides
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue