Skip to content

Class TeardownAttribute

Namespace: Belay.Attributes
Assembly: Belay.Attributes.dll

Marks a method to be executed during device disconnection or disposal. Methods decorated with this attribute are automatically called when the device connection is terminated, providing cleanup and resource management capabilities.

csharp
[AttributeUsage(AttributeTargets.Method)]
public sealed class TeardownAttribute : Attribute

Inheritance

objectAttributeTeardownAttribute

Inherited Members

Attribute.Equals(object?), Attribute.GetCustomAttribute(Assembly, Type), Attribute.GetCustomAttribute(Assembly, Type, bool), Attribute.GetCustomAttribute(MemberInfo, Type), Attribute.GetCustomAttribute(MemberInfo, Type, bool), Attribute.GetCustomAttribute(Module, Type), Attribute.GetCustomAttribute(Module, Type, bool), Attribute.GetCustomAttribute(ParameterInfo, Type), Attribute.GetCustomAttribute(ParameterInfo, Type, bool), Attribute.GetCustomAttributes(Assembly), Attribute.GetCustomAttributes(Assembly, bool), Attribute.GetCustomAttributes(Assembly, Type), Attribute.GetCustomAttributes(Assembly, Type, bool), Attribute.GetCustomAttributes(MemberInfo), Attribute.GetCustomAttributes(MemberInfo, bool), Attribute.GetCustomAttributes(MemberInfo, Type), Attribute.GetCustomAttributes(MemberInfo, Type, bool), Attribute.GetCustomAttributes(Module), Attribute.GetCustomAttributes(Module, bool), Attribute.GetCustomAttributes(Module, Type), Attribute.GetCustomAttributes(Module, Type, bool), Attribute.GetCustomAttributes(ParameterInfo), Attribute.GetCustomAttributes(ParameterInfo, bool), Attribute.GetCustomAttributes(ParameterInfo, Type), Attribute.GetCustomAttributes(ParameterInfo, Type, bool), Attribute.GetHashCode(), Attribute.IsDefaultAttribute(), Attribute.IsDefined(Assembly, Type), Attribute.IsDefined(Assembly, Type, bool), Attribute.IsDefined(MemberInfo, Type), Attribute.IsDefined(MemberInfo, Type, bool), Attribute.IsDefined(Module, Type), Attribute.IsDefined(Module, Type, bool), Attribute.IsDefined(ParameterInfo, Type), Attribute.IsDefined(ParameterInfo, Type, bool), Attribute.Match(object?), Attribute.TypeId, object.Equals(object?), object.Equals(object?, object?), object.GetHashCode(), object.GetType(), object.ReferenceEquals(object?, object?), object.ToString()

Examples

Hardware Resource Cleanup

public class MotorController : Device
{
    [Setup]
    private async Task InitializeMotorsAsync()
    {
        await ExecuteAsync(@"
            import machine
            motor_left = machine.PWM(machine.Pin(12))
            motor_right = machine.PWM(machine.Pin(13))
            motor_left.freq(1000)
            motor_right.freq(1000)
        ");
    }

    [Teardown]
    private async Task StopMotorsAsync()
    {
        await ExecuteAsync(@"
            # Safely stop motors before disconnect
            try:
                if 'motor_left' in globals():
                    motor_left.duty_u16(0)
                    motor_left.deinit()
                if 'motor_right' in globals():
                    motor_right.duty_u16(0)
                    motor_right.deinit()
                print('Motors stopped safely')
            except Exception as e:
                print(f'Motor cleanup error: {e}')
        ");
    }
}

State Persistence

public class DataLogger : Device
{
    [Teardown]
    private async Task SaveDataAsync()
    {
        await ExecuteAsync(@"
            import json

            try:
                # Save any pending data before disconnect
                if 'pending_data' in globals() and pending_data:
                    with open('data_backup.json', 'w') as f:
                        json.dump(pending_data, f)
                    print(f'Saved {len(pending_data)} pending records')

                # Update status file
                status = {
                    'last_disconnect': time.time(),
                    'clean_shutdown': True
                }
                with open('status.json', 'w') as f:
                    json.dump(status, f)

            except Exception as e:
                print(f'Data save error: {e}')
        ");
    }
}

Multi-Stage Teardown

public class ComplexDevice : Device
{
    [Teardown(Order = 1)] // Execute first
    private async Task StopBackgroundTasksAsync()
    {
        await ExecuteAsync(@"
            # Stop background threads
            monitoring_active = False
            data_collection_active = False

            # Wait briefly for threads to notice
            import time
            time.sleep_ms(100)
        ");
    }

    [Teardown(Order = 2)] // Execute second
    private async Task SaveStateAsync()
    {
        await ExecuteAsync(@"
            # Save current state
            save_device_state()
            flush_data_buffers()
        ");
    }

    [Teardown(Order = 3)] // Execute last
    private async Task CleanupHardwareAsync()
    {
        await ExecuteAsync(@"
            # Final hardware cleanup
            disable_all_outputs()
            release_hardware_resources()
        ");
    }
}

Error-Resilient Teardown

public class RobustDevice : Device
{
    [Teardown(IgnoreErrors = true)]
    private async Task BestEffortCleanupAsync()
    {
        await ExecuteAsync(@"
            # Clean up everything we can, ignore individual failures
            cleanup_tasks = [
                lambda: cleanup_sensors(),
                lambda: stop_background_threads(),
                lambda: save_critical_data(),
                lambda: disable_hardware()
            ]

            for task in cleanup_tasks:
                try:
                    task()
                except Exception as e:
                    print(f'Cleanup task failed: {e}')

            print('Best-effort cleanup completed')
        ");
    }
}

Remarks

The ensures proper cleanup when device connections end, whether due to explicit disconnection, network issues, or application shutdown. This is essential for releasing hardware resources, saving state, and graceful shutdown of background operations.

Teardown methods are executed in reverse declaration order within a class, with derived class teardown methods running before base class teardown methods. This ensures proper cleanup hierarchy and dependency management.

Teardown execution characteristics:

  • Always executes, even if setup or other operations failed
  • Has limited time to complete before forcible disconnection
  • Should be robust against partial initialization states
  • Failures are logged but do not prevent disconnection

Constructors

TeardownAttribute()

Initializes a new instance of the class.

Properties

Critical

Gets or sets a value indicating whether gets or sets whether this teardown method is critical and must execute even in emergency disconnection scenarios.

IgnoreErrors

Gets or sets a value indicating whether gets or sets whether errors in this teardown method should be ignored. When true, exceptions from this method will be logged but will not prevent other teardown methods from executing or the disconnection from proceeding.

Order

Gets or sets the order in which this teardown method should be executed relative to other teardown methods in the same class.

TimeoutMs

Gets or sets the timeout for teardown method execution in milliseconds. Teardown operations have limited time to complete before forcible disconnection.

Methods

ToString()

Returns a string that represents the current .

Released under the Apache License 2.0.