mirror of
https://github.com/ICDSystems/ICD.Common.Utils.git
synced 2026-01-11 19:44:55 +00:00
feat[Types]: Add NotifyFlagsChanged, with abstract and generic classes
This commit is contained in:
131
ICD.Common.Utils.Tests/Types/GenericNotifyFlagsChangedTest.cs
Normal file
131
ICD.Common.Utils.Tests/Types/GenericNotifyFlagsChangedTest.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
using ICD.Common.Utils.Types;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace ICD.Common.Utils.Tests.Types
|
||||
{
|
||||
[TestFixture]
|
||||
public class GenericNotifyFlagsChangedTest
|
||||
{
|
||||
[Flags]
|
||||
private enum eTestFlagsEnum
|
||||
{
|
||||
None = 0,
|
||||
A = 1,
|
||||
B = 2,
|
||||
C = 4,
|
||||
D = 32,
|
||||
BandC = B | C
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSingleFlags()
|
||||
{
|
||||
List<GenericEventArgs<eTestFlagsEnum>> addedFlags = new List<GenericEventArgs<eTestFlagsEnum>>();
|
||||
List<GenericEventArgs<eTestFlagsEnum>> removedFlags = new List<GenericEventArgs<eTestFlagsEnum>>();
|
||||
|
||||
GenericNotifyFlagsChanged<eTestFlagsEnum> genericNotify = new GenericNotifyFlagsChanged<eTestFlagsEnum>();
|
||||
|
||||
genericNotify.OnFlagsSet += (sender, args) => addedFlags.Add(args);
|
||||
genericNotify.OnFlagsUnset += (sender, args) => removedFlags.Add(args);
|
||||
|
||||
// Initial State
|
||||
Assert.AreEqual(0, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
|
||||
// Add No flags
|
||||
genericNotify.Data = eTestFlagsEnum.None;
|
||||
Assert.AreEqual(0, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
|
||||
// Add Flag
|
||||
genericNotify.Data = eTestFlagsEnum.B;
|
||||
Assert.AreEqual(1, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.B, addedFlags[0].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.B, genericNotify.Data);
|
||||
|
||||
// Add Another Flag
|
||||
genericNotify.Data |= eTestFlagsEnum.C;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.C, addedFlags[1].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.B | eTestFlagsEnum.C, genericNotify.Data);
|
||||
|
||||
// Remove a Flag
|
||||
genericNotify.Data = genericNotify.Data & ~ eTestFlagsEnum.B;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(1, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.B, removedFlags[0].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.C, genericNotify.Data);
|
||||
|
||||
// Add Already Existing Flags
|
||||
genericNotify.Data |= eTestFlagsEnum.C;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(1, removedFlags.Count);
|
||||
|
||||
// Clear Flags
|
||||
genericNotify.Data = eTestFlagsEnum.None;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(2, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.C, removedFlags[1].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.None, genericNotify.Data);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestMultipleFlags()
|
||||
{
|
||||
List<GenericEventArgs<eTestFlagsEnum>> addedFlags = new List<GenericEventArgs<eTestFlagsEnum>>();
|
||||
List<GenericEventArgs<eTestFlagsEnum>> removedFlags = new List<GenericEventArgs<eTestFlagsEnum>>();
|
||||
|
||||
GenericNotifyFlagsChanged<eTestFlagsEnum> genericNotify = new GenericNotifyFlagsChanged<eTestFlagsEnum>();
|
||||
|
||||
genericNotify.OnFlagsSet += (sender, args) => addedFlags.Add(args);
|
||||
genericNotify.OnFlagsUnset += (sender, args) => removedFlags.Add(args);
|
||||
|
||||
// Initial State
|
||||
Assert.AreEqual(0, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
|
||||
// Add No flags
|
||||
genericNotify.Data = eTestFlagsEnum.None;
|
||||
Assert.AreEqual(0, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
|
||||
// Add Flag
|
||||
genericNotify.Data = eTestFlagsEnum.B | eTestFlagsEnum.D;
|
||||
Assert.AreEqual(1, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.B | eTestFlagsEnum.D, addedFlags[0].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.B | eTestFlagsEnum.D, genericNotify.Data);
|
||||
|
||||
// Add Another Flag
|
||||
genericNotify.Data |= eTestFlagsEnum.C;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(0, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.C, addedFlags[1].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.B | eTestFlagsEnum.C | eTestFlagsEnum.D, genericNotify.Data);
|
||||
|
||||
// Remove a Flag
|
||||
genericNotify.Data = eTestFlagsEnum.D;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(1, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.B | eTestFlagsEnum.C, removedFlags[0].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.D, genericNotify.Data);
|
||||
|
||||
// Add Already Existing Flags
|
||||
genericNotify.Data |= eTestFlagsEnum.D;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(1, removedFlags.Count);
|
||||
|
||||
// Clear Flags
|
||||
genericNotify.Data = eTestFlagsEnum.None;
|
||||
Assert.AreEqual(2, addedFlags.Count);
|
||||
Assert.AreEqual(2, removedFlags.Count);
|
||||
Assert.AreEqual(eTestFlagsEnum.D, removedFlags[1].Data);
|
||||
Assert.AreEqual(eTestFlagsEnum.None, genericNotify.Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -242,6 +242,8 @@
|
||||
<Compile Include="TimeZoneInfo\IcdTimeZoneInfoAdjustmentRule.cs" />
|
||||
<Compile Include="TimeZoneInfo\IcdTimeZoneInfoTransitionTime.cs" />
|
||||
<Compile Include="TryUtils.cs" />
|
||||
<Compile Include="Types\AbstractNotifyFlagsChanged.cs" />
|
||||
<Compile Include="Types\GenericNotifyFlagsChanged.cs" />
|
||||
<Compile Include="UriQueryBuilder.cs" />
|
||||
<Compile Include="UriUtils.cs" />
|
||||
<Compile Include="VersionSpan.cs" />
|
||||
|
||||
79
ICD.Common.Utils/Types/AbstractNotifyFlagsChanged.cs
Normal file
79
ICD.Common.Utils/Types/AbstractNotifyFlagsChanged.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
|
||||
namespace ICD.Common.Utils.Types
|
||||
{
|
||||
public abstract class AbstractNotifyFlagsChanged<T> where T : struct, IConvertible
|
||||
{
|
||||
private T m_Data;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when flags are set on the data
|
||||
/// </summary>
|
||||
public event EventHandler<GenericEventArgs<T>> OnFlagsSet;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when flags are unset on the data
|
||||
/// </summary>
|
||||
public event EventHandler<GenericEventArgs<T>> OnFlagsUnset;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the data changes
|
||||
/// </summary>
|
||||
public event EventHandler<GenericEventArgs<T>> OnChange;
|
||||
|
||||
/// <summary>
|
||||
/// Data
|
||||
/// </summary>
|
||||
public T Data
|
||||
{
|
||||
get { return m_Data; }
|
||||
set
|
||||
{
|
||||
if (DataIsEqual(m_Data, value))
|
||||
return;
|
||||
|
||||
int intData = GetIntValue(m_Data);
|
||||
int intValue = GetIntValue(value);
|
||||
|
||||
int setFlags = intValue & ~intData;
|
||||
int unsetFlags = intData & ~intValue;
|
||||
|
||||
m_Data = value;
|
||||
|
||||
OnChange.Raise(this, value);
|
||||
|
||||
if (setFlags != 0)
|
||||
OnFlagsSet.Raise(this, GetEnumValue(setFlags));
|
||||
if (unsetFlags != 0)
|
||||
OnFlagsUnset.Raise(this, GetEnumValue(unsetFlags));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the enum to the backing int value
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract int GetIntValue(T value);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the backing int value to enum
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
protected abstract T GetEnumValue(int value);
|
||||
|
||||
/// <summary>
|
||||
/// Checks enums for equality
|
||||
/// Override for performance improvements
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual bool DataIsEqual(T a, T b)
|
||||
{
|
||||
return GetIntValue(a) == GetIntValue(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
34
ICD.Common.Utils/Types/GenericNotifyFlagsChanged.cs
Normal file
34
ICD.Common.Utils/Types/GenericNotifyFlagsChanged.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using ICD.Common.Utils.EventArguments;
|
||||
|
||||
namespace ICD.Common.Utils.Types
|
||||
{
|
||||
/// <summary>
|
||||
/// Class to raise events when flags are set and unset on the data
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public sealed class GenericNotifyFlagsChanged<T> : AbstractNotifyFlagsChanged<T> where T : struct, IConvertible
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts the enum to the backing int value
|
||||
/// Override for performance improvements
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
protected override int GetIntValue(T value)
|
||||
{
|
||||
return (int)(object)value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the backing int value to enum
|
||||
/// Override for performance improvements
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
protected override T GetEnumValue(int value)
|
||||
{
|
||||
return (T)(object)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user