Merge branch 'dev' into test-pool

This commit is contained in:
DCFApixels 2025-03-14 22:03:54 +08:00
commit fde6983160
9 changed files with 68 additions and 67 deletions

View File

@ -432,7 +432,7 @@ namespace DCFApixels.DragonECS
{ {
ref PageSlot page = ref _sparsePages[entityID >> PageSlot.SHIFT]; ref PageSlot page = ref _sparsePages[entityID >> PageSlot.SHIFT];
#if DEBUG && DRAGONECS_DEEP_DEBUG #if DEBUG && DRAGONECS_DEEP_DEBUG
if (page.Count == 0) { throw new Exception(); } if (page.Count == 0) { Throw.DeepDebugException(); }
#endif #endif
if (page.Count == 1) if (page.Count == 1)
{ {
@ -442,7 +442,7 @@ namespace DCFApixels.DragonECS
{ {
int localEntityID = entityID & PageSlot.MASK; int localEntityID = entityID & PageSlot.MASK;
#if DEBUG && DRAGONECS_DEEP_DEBUG #if DEBUG && DRAGONECS_DEEP_DEBUG
if (page.Indexes[localEntityID] == 0) { throw new Exception(); } if (page.Indexes[localEntityID] == 0) { Throw.DeepDebugException(); }
#endif #endif
page.Indexes[localEntityID] = index; page.Indexes[localEntityID] = index;
} }
@ -1005,10 +1005,10 @@ namespace DCFApixels.DragonECS
int uniqueCount = 0; int uniqueCount = 0;
foreach (var entityID in span) foreach (var entityID in span)
{ {
#if DEBUG && DRAGONECS_DEEP_DEBUG
HashSet<int> thisHS = new HashSet<int>(); HashSet<int> thisHS = new HashSet<int>();
ToCollection(thisHS); ToCollection(thisHS);
#if DEBUG && DRAGONECS_DEEP_DEBUG if (thisHS.Contains(entityID) && Has(entityID) == false) { Throw.DeepDebugException(); }
if (thisHS.Contains(entityID) && Has(entityID) == false) { throw new Exception(); }
#endif #endif
if (Has(entityID)) if (Has(entityID))
{ {

View File

@ -56,7 +56,7 @@ namespace DCFApixels.DragonECS
if (!runnerType.GetInterfaces().Any(o => o == targetInterface)) if (!runnerType.GetInterfaces().Any(o => o == targetInterface))
{ {
throw new EcsRunnerImplementationException($"Runner {GetGenericTypeFullName(runnerType, 1)} does not implement interface {GetGenericTypeFullName(baseTypeArgument, 1)}."); throw new ImplementationException($"Runner {GetGenericTypeFullName(runnerType, 1)} does not implement interface {GetGenericTypeFullName(baseTypeArgument, 1)}.");
} }
#pragma warning restore IL2070 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The parameter of method does not have matching annotations. #pragma warning restore IL2070 // 'this' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method. The parameter of method does not have matching annotations.
#endif #endif

View File

@ -343,14 +343,14 @@ namespace DCFApixels.DragonECS
public void Inc(EcsTypeCode typeCode) public void Inc(EcsTypeCode typeCode)
{ {
#if DEBUG || ENABLE_DRAGONECS_ASSERT_CHEKS #if DEBUG || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_inc.Contains(typeCode) || _exc.Contains(typeCode)) { Throw.ConstraintIsAlreadyContainedInMask(); } if (_inc.Contains(typeCode) || _exc.Contains(typeCode)) { Throw.ConstraintIsAlreadyContainedInMask(typeCode); }
#endif #endif
_inc.Add(typeCode); _inc.Add(typeCode);
} }
public void Exc(EcsTypeCode typeCode) public void Exc(EcsTypeCode typeCode)
{ {
#if DEBUG || ENABLE_DRAGONECS_ASSERT_CHEKS #if DEBUG || ENABLE_DRAGONECS_ASSERT_CHEKS
if (_inc.Contains(typeCode) || _exc.Contains(typeCode)) { Throw.ConstraintIsAlreadyContainedInMask(); } if (_inc.Contains(typeCode) || _exc.Contains(typeCode)) { Throw.ConstraintIsAlreadyContainedInMask(typeCode); }
#endif #endif
_exc.Add(typeCode); _exc.Add(typeCode);
} }
@ -494,9 +494,9 @@ namespace DCFApixels.DragonECS
#if DEBUG #if DEBUG
private static void CheckConstraints(EcsTypeCode[] incs, EcsTypeCode[] excs) private static void CheckConstraints(EcsTypeCode[] incs, EcsTypeCode[] excs)
{ {
if (CheckRepeats(incs)) { throw new EcsFrameworkException("The values in the Include constraints are repeated."); } if (CheckRepeats(incs)) { throw new ArgumentException("The values in the Include constraints are repeated."); }
if (CheckRepeats(excs)) { throw new EcsFrameworkException("The values in the Exclude constraints are repeated."); } if (CheckRepeats(excs)) { throw new ArgumentException("The values in the Exclude constraints are repeated."); }
if (OverlapsArray(incs, excs)) { throw new EcsFrameworkException("Conflicting Include and Exclude constraints."); } if (OverlapsArray(incs, excs)) { throw new ArgumentException("Conflicting Include and Exclude constraints."); }
} }
private static bool CheckRepeats(EcsTypeCode[] array) private static bool CheckRepeats(EcsTypeCode[] array)
{ {

View File

@ -57,7 +57,7 @@ namespace DCFApixels.DragonECS
{ {
if (_nodes.ContainsKey(requiredInjectionType) == false) if (_nodes.ContainsKey(requiredInjectionType) == false)
{ {
throw new EcsInjectionException($"A systems in the pipeline implements IEcsInject<{requiredInjectionType.Name}> interface, but no suitable injection node was found in the Injector. To create a node, use Injector.AddNode<{requiredInjectionType.Name}>() or implement the IInjectionUnit interface for type {objType.Name}."); throw new InjectionException($"A systems in the pipeline implements IEcsInject<{requiredInjectionType.Name}> interface, but no suitable injection node was found in the Injector. To create a node, use Injector.AddNode<{requiredInjectionType.Name}>() or implement the IInjectionUnit interface for type {objType.Name}.");
} }
} }
} }
@ -84,7 +84,7 @@ namespace DCFApixels.DragonECS
{ {
return node.CurrentInjectedDependencyRaw; return node.CurrentInjectedDependencyRaw;
} }
throw new EcsInjectionException($"The injection graph is missing a node for {type.Name} type. To create a node, use the Injector.AddNode<{type.Name}>() method directly in the injector or in the implementation of the IInjectionUnit for {type.Name}."); throw new InjectionException($"The injection graph is missing a node for {type.Name} type. To create a node, use the Injector.AddNode<{type.Name}>() method directly in the injector or in the implementation of the IInjectionUnit for {type.Name}.");
} }
public void AddNode<T>() public void AddNode<T>()
{ {
@ -232,7 +232,7 @@ namespace DCFApixels.DragonECS
} }
} }
Throw.UndefinedException(); Throw.UndefinedException();
return _source; return default;
} }
public Injector Build(EcsPipeline pipeline) public Injector Build(EcsPipeline pipeline)
{ {

View File

@ -96,7 +96,7 @@ namespace DCFApixels.DragonECS.Internal
{ {
if ((uint)start > (uint)Length) if ((uint)start > (uint)Length)
{ {
throw new ArgumentOutOfRangeException(); Throw.ArgumentOutOfRange();
} }
return new UnsafeArray<T>(ptr + start, Length - start); return new UnsafeArray<T>(ptr + start, Length - start);
} }
@ -106,7 +106,7 @@ namespace DCFApixels.DragonECS.Internal
{ {
if ((uint)start > (uint)Length || (uint)length > (uint)(Length - start)) if ((uint)start > (uint)Length || (uint)length > (uint)(Length - start))
{ {
throw new ArgumentOutOfRangeException(); Throw.ArgumentOutOfRange();
} }
return new UnsafeArray<T>(ptr + start, length); return new UnsafeArray<T>(ptr + start, length);
} }

View File

@ -32,27 +32,27 @@ namespace DCFApixels.DragonECS.PoolsCore
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowDifferentTypes() public static void ThrowDifferentTypes()
{ {
throw new EcsFrameworkException($"The component instance type and the pool component type are different."); throw new ArgumentException($"The component instance type and the pool component type are different.");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowAlreadyHasComponent<T>(int entityID) public static void ThrowAlreadyHasComponent<T>(int entityID)
{ {
throw new EcsFrameworkException($"Entity({entityID}) already has component {EcsDebugUtility.GetGenericTypeName<T>()}."); throw new ArgumentException($"Entity({entityID}) already has component {EcsDebugUtility.GetGenericTypeName<T>()}.");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowNotHaveComponent<T>(int entityID) public static void ThrowNotHaveComponent<T>(int entityID)
{ {
throw new EcsFrameworkException($"Entity({entityID}) has no component {EcsDebugUtility.GetGenericTypeName<T>()}."); throw new ArgumentException($"Entity({entityID}) has no component {EcsDebugUtility.GetGenericTypeName<T>()}.");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowAlreadyHasComponent(Type type, int entityID) public static void ThrowAlreadyHasComponent(Type type, int entityID)
{ {
throw new EcsFrameworkException($"Entity({entityID}) already has component {EcsDebugUtility.GetGenericTypeName(type)}."); throw new ArgumentException($"Entity({entityID}) already has component {EcsDebugUtility.GetGenericTypeName(type)}.");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowNotHaveComponent(Type type, int entityID) public static void ThrowNotHaveComponent(Type type, int entityID)
{ {
throw new EcsFrameworkException($"Entity({entityID}) has no component {EcsDebugUtility.GetGenericTypeName(type)}."); throw new ArgumentException($"Entity({entityID}) has no component {EcsDebugUtility.GetGenericTypeName(type)}.");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowNullListener() public static void ThrowNullListener()
@ -62,7 +62,7 @@ namespace DCFApixels.DragonECS.PoolsCore
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowPoolLocked() public static void ThrowPoolLocked()
{ {
throw new EcsFrameworkException("The pool is currently locked and cannot add or remove components."); throw new InvalidOperationException("The pool is currently locked and cannot add or remove components.");
} }
} }
#endregion #endregion
@ -87,7 +87,7 @@ namespace DCFApixels.DragonECS.Internal
{ {
get get
{ {
#if (DEBUG) #if DEBUG
throw new NullInstanceException(); throw new NullInstanceException();
#else #else
return EcsWorld.GetWorld(0); return EcsWorld.GetWorld(0);
@ -105,25 +105,25 @@ namespace DCFApixels.DragonECS.Internal
} }
void IEcsPool.Del(int entityID) void IEcsPool.Del(int entityID)
{ {
#if (DEBUG) #if DEBUG
throw new NullInstanceException(); throw new NullInstanceException();
#endif #endif
} }
void IEcsPool.AddEmpty(int entityID) void IEcsPool.AddEmpty(int entityID)
{ {
#if (DEBUG) #if DEBUG
throw new NullInstanceException(); throw new NullInstanceException();
#endif #endif
} }
void IEcsPool.AddRaw(int entityID, object dataRaw) void IEcsPool.AddRaw(int entityID, object dataRaw)
{ {
#if (DEBUG) #if DEBUG
throw new NullInstanceException(); throw new NullInstanceException();
#endif #endif
} }
object IEcsReadonlyPool.GetRaw(int entityID) object IEcsReadonlyPool.GetRaw(int entityID)
{ {
#if (DEBUG) #if DEBUG
throw new NullInstanceException(); throw new NullInstanceException();
#else #else
return null; return null;
@ -131,25 +131,25 @@ namespace DCFApixels.DragonECS.Internal
} }
void IEcsPool.SetRaw(int entity, object dataRaw) void IEcsPool.SetRaw(int entity, object dataRaw)
{ {
#if (DEBUG) #if DEBUG
throw new NullInstanceException(); throw new NullInstanceException();
#endif #endif
} }
void IEcsReadonlyPool.Copy(int fromEntityID, int toEntityID) void IEcsReadonlyPool.Copy(int fromEntityID, int toEntityID)
{ {
#if (DEBUG) #if DEBUG
throw new NullInstanceException(); throw new NullInstanceException();
#endif #endif
} }
void IEcsReadonlyPool.Copy(int fromEntityID, EcsWorld toWorld, int toEntityID) void IEcsReadonlyPool.Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
{ {
#if (DEBUG) #if DEBUG
throw new NullInstanceException(); throw new NullInstanceException();
#endif #endif
} }
void IEcsPool.ClearAll() void IEcsPool.ClearAll()
{ {
#if (DEBUG) #if DEBUG
throw new NullInstanceException(); throw new NullInstanceException();
#endif #endif
} }

View File

@ -64,7 +64,7 @@ namespace DCFApixels.DragonECS
{ {
if (_isInvalidType) if (_isInvalidType)
{ {
throw new EcsFrameworkException($"{typeof(T).Name} type must not contain any data."); throw new Exception($"{typeof(T).Name} type must not contain any data.");
} }
} }
#endif #endif

View File

@ -39,7 +39,7 @@ namespace DCFApixels.DragonECS
return; return;
} }
} }
throw new EcsFrameworkException($"Using component {componentType.ToMeta().TypeName} is not allowed in the {worldType.ToMeta().TypeName} world."); throw new InvalidOperationException($"Using component {componentType.ToMeta().TypeName} is not allowed in the {worldType.ToMeta().TypeName} world.");
} }
} }
} }

View File

@ -7,32 +7,32 @@ using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
[Serializable] [Serializable]
public class EcsFrameworkException : Exception public class DeepDebugException : Exception
{ {
public EcsFrameworkException() { } public DeepDebugException() { }
public EcsFrameworkException(string message) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message) { } public DeepDebugException(string message) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message) { }
public EcsFrameworkException(string message, Exception inner) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message, inner) { } public DeepDebugException(string message, Exception inner) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message, inner) { }
} }
[Serializable] [Serializable]
public class NullInstanceException : EcsFrameworkException public class NullInstanceException : Exception
{ {
public NullInstanceException() { } public NullInstanceException() { }
public NullInstanceException(string message) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message) { } public NullInstanceException(string message) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message) { }
public NullInstanceException(string message, Exception inner) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message, inner) { } public NullInstanceException(string message, Exception inner) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message, inner) { }
} }
[Serializable] [Serializable]
public class EcsRunnerImplementationException : EcsFrameworkException public class ImplementationException : Exception
{ {
public EcsRunnerImplementationException() { } public ImplementationException() { }
public EcsRunnerImplementationException(string message) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message) { } public ImplementationException(string message) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message) { }
public EcsRunnerImplementationException(string message, Exception inner) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message, inner) { } public ImplementationException(string message, Exception inner) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message, inner) { }
} }
[Serializable] [Serializable]
public class EcsInjectionException : Exception public class InjectionException : Exception
{ {
public EcsInjectionException() { } public InjectionException() { }
public EcsInjectionException(string message) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message) { } public InjectionException(string message) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message) { }
public EcsInjectionException(string message, Exception inner) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message, inner) { } public InjectionException(string message, Exception inner) : base(EcsConsts.EXCEPTION_MESSAGE_PREFIX + message, inner) { }
} }
} }
@ -41,24 +41,20 @@ namespace DCFApixels.DragonECS.Internal
internal static class Throw internal static class Throw
{ {
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
internal static void ConstraintIsAlreadyContainedInMask() internal static void ConstraintIsAlreadyContainedInMask(EcsTypeCode typeCode)
{ {
throw new EcsFrameworkException($"The constraint is already contained in the mask."); string typeName = EcsDebugUtility.GetGenericTypeName(EcsTypeCodeManager.FindTypeOfCode(typeCode).Type);
} throw new ArgumentException($"The {typeName} constraint is already contained in the mask.");
[MethodImpl(MethodImplOptions.NoInlining)]
internal static void ConstraintIsAlreadyContainedInMask(Type type)
{
throw new EcsFrameworkException($"The {EcsDebugUtility.GetGenericTypeName(type)} constraint is already contained in the mask.");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
internal static void Group_AlreadyContains(int entityID) internal static void Group_AlreadyContains(int entityID)
{ {
throw new EcsFrameworkException($"This group already contains entity {entityID}."); throw new ArgumentException($"This group already contains entity {entityID}.");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
internal static void Group_DoesNotContain(int entityID) internal static void Group_DoesNotContain(int entityID)
{ {
throw new EcsFrameworkException($"This group does not contain entity {entityID}."); throw new ArgumentException($"This group does not contain entity {entityID}.");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
internal static void Group_ArgumentDifferentWorldsException() internal static void Group_ArgumentDifferentWorldsException()
@ -69,57 +65,57 @@ namespace DCFApixels.DragonECS.Internal
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
internal static void Pipeline_MethodCalledAfterInitialisation(string methodName) internal static void Pipeline_MethodCalledAfterInitialisation(string methodName)
{ {
throw new MethodAccessException($"It is forbidden to call {methodName}, after initialization {nameof(EcsPipeline)}."); throw new InvalidOperationException($"It is forbidden to call {methodName}, after initialization {nameof(EcsPipeline)}.");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
internal static void Pipeline_MethodCalledBeforeInitialisation(string methodName) internal static void Pipeline_MethodCalledBeforeInitialisation(string methodName)
{ {
throw new MethodAccessException($"It is forbidden to call {methodName}, before initialization {nameof(EcsPipeline)}."); throw new InvalidOperationException($"It is forbidden to call {methodName}, before initialization {nameof(EcsPipeline)}.");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
internal static void Pipeline_MethodCalledAfterDestruction(string methodName) internal static void Pipeline_MethodCalledAfterDestruction(string methodName)
{ {
throw new MethodAccessException($"It is forbidden to call {methodName}, after destroying {nameof(EcsPipeline)}."); throw new InvalidOperationException($"It is forbidden to call {methodName}, after destroying {nameof(EcsPipeline)}.");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
internal static void World_InvalidIncrementComponentsBalance() internal static void World_InvalidIncrementComponentsBalance()
{ {
throw new MethodAccessException("Invalid increment components balance."); throw new InvalidOperationException("Invalid increment components balance.");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
internal static void World_GroupDoesNotBelongWorld() internal static void World_GroupDoesNotBelongWorld()
{ {
throw new MethodAccessException("The Group does not belong in this world."); throw new InvalidOperationException("The Group does not belong in this world.");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void World_MaskDoesntBelongWorld() public static void World_MaskDoesntBelongWorld()
{ {
throw new EcsFrameworkException($"The mask doesn't belong in this world"); throw new InvalidOperationException($"The mask doesn't belong in this world");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void World_EntityIsNotContained(int entityID) public static void World_EntityIsNotContained(int entityID)
{ {
throw new EcsFrameworkException($"An entity with identifier {entityID} is not contained in this world"); throw new ArgumentException($"An entity with identifier {entityID} is not contained in this world");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void World_EntityIsAlreadyСontained(int entityID) public static void World_EntityIsAlreadyСontained(int entityID)
{ {
throw new EcsFrameworkException($"An entity with identifier {entityID} is already contained in this world"); throw new ArgumentException($"An entity with identifier {entityID} is already contained in this world");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void World_PoolAlreadyCreated() public static void World_PoolAlreadyCreated()
{ {
throw new EcsFrameworkException("The pool has already been created."); throw new ArgumentException("The pool has already been created.");
} }
public static void World_WorldCantBeDestroyed() public static void World_WorldCantBeDestroyed()
{ {
throw new EcsFrameworkException("This world can't be destroyed"); throw new InvalidOperationException("This world can't be destroyed");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
public static void World_MethodCalledAfterEntityCreation(string methodName) public static void World_MethodCalledAfterEntityCreation(string methodName)
{ {
throw new EcsFrameworkException($"The method {methodName} can only be executed before creating entities in the world."); throw new InvalidOperationException($"The method {methodName} can only be executed before creating entities in the world.");
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
@ -127,11 +123,11 @@ namespace DCFApixels.DragonECS.Internal
{ {
if (entity.IsNull) if (entity.IsNull)
{ {
throw new EcsFrameworkException($"The {entity} is null."); throw new InvalidOperationException($"The {entity} is null.");
} }
else else
{ {
throw new EcsFrameworkException($"The {entity} is not alive."); throw new InvalidOperationException($"The {entity} is not alive.");
} }
} }
@ -162,6 +158,11 @@ namespace DCFApixels.DragonECS.Internal
{ {
throw new Exception(); throw new Exception();
} }
[MethodImpl(MethodImplOptions.NoInlining)]
internal static void DeepDebugException()
{
throw new DeepDebugException();
}
internal static void OpeningClosingMethodsBalanceError() internal static void OpeningClosingMethodsBalanceError()
{ {
throw new InvalidOperationException("Error of opening - closing methods. Closing method was called more often than opening method."); throw new InvalidOperationException("Error of opening - closing methods. Closing method was called more often than opening method.");