Skip to content

StorageObject Class

Naveen Dharmathunga edited this page Jan 19, 2026 · 1 revision

StorageObject Class

Provides an abstract base class for file system storage objects, encapsulating common functionality such as path validation, resource management, and change notification.

Namespace: Rheo.Storage.Core

Assembly: Rheo.Storage.dll

Definition

public abstract class StorageObject : IStorageObject

Inheritance

Object → StorageObject

Derived

  • FileHandler
  • DirectoryHandler

Implements

Constructors

Constructor Description
StorageObject(String, Boolean) Initializes a new instance of the StorageObject class with the specified file system path, optionally validating and creating the parent directory if necessary.

Properties

Property Type Description
Information IStorageInformation Gets or sets metadata information about the storage object.
Name String Gets the name of the storage object, typically the file or directory name.
ParentDirectory String Gets the full path of the parent directory for the current file or directory.
FullPath String Gets or sets the full path of the file or directory.
IsDisposed Boolean Gets a value indicating whether this storage object has been disposed.
StateLock Lock Gets the internal lock object used to synchronize access to the state of this storage object.

Events

Event Description
Changed Occurs when the storage content changes.

Methods

Method Description
Dispose() Releases all resources used by the current instance of the class.
GetBufferSize() Calculates the recommended buffer size based on the current storage information.
ThrowIfDisposed() Throws an ObjectDisposedException if this storage object has been disposed.
ToString() Returns a string representation of the storage object.
GetValidPath(String) Validates the specified path and returns its absolute form if it meets the required criteria.
WaitForFileAvailableAsync(String, Int32, Int32, CancellationToken) Asynchronously waits until the specified file becomes available for exclusive read/write access, or until the operation times out.
WaitForFileAvailable(String, Int32, Int32) Waits for a file to become available for access within a specified timeout period.
WaitForDirectoryAvailableAsync(String, Int32, Int32, CancellationToken) Asynchronously waits until the specified directory becomes available for access or until the operation times out.
WaitForDirectoryAvailable(String, Int32, Int32) Waits for the specified directory to become available within a given timeout period.

Remarks

The StorageObject class serves as a foundation for implementing file- or directory-based storage abstractions. It manages the association with a file system path, ensures the existence of parent directories, and provides thread-safe state management. Derived classes should implement the required members to provide specific storage behaviors. The class supports change notification through the Changed event and implements resource cleanup via IDisposable. Instances should not be used after they have been disposed.

This class uses the Curiously Recurring Template Pattern (CRTP) to provide common functionality while allowing derived classes to specialize behavior.


Constructor Details

StorageObject(String, Boolean)

Initializes a new instance of the StorageObject class with the specified file system path, optionally validating and creating the parent directory if necessary.

protected StorageObject(string path, bool validated)

Parameters

path String

The file system path to associate with the storage object. This can be either a validated or unvalidated path, depending on the value of the validated parameter.

validated Boolean

true to indicate that the path has already been validated; false to validate the path and ensure the parent directory exists before use.

Remarks

If validated is false, the constructor validates the provided path and creates the parent directory if it does not already exist. This ensures that the storage object is always associated with a valid and accessible file system location.


Property Details

Information

Gets or sets metadata information about the storage object, such as size, attributes, and timestamps.

public abstract IStorageInformation Information { get; protected set; }

Property Value

IStorageInformation

An object containing detailed metadata about the storage item.

Remarks

This property must be implemented by derived classes. It is automatically updated when changes are detected through the Changed event.


Name

Gets the name of the storage object, typically the file or directory name.

public abstract string Name { get; }

Property Value

String

The name of the file or directory without the path.

Remarks

This property must be implemented by derived classes.


ParentDirectory

Gets the full path of the parent directory for the current file or directory.

public string ParentDirectory { get; }

Property Value

String

The absolute path to the parent directory.


FullPath

Gets or sets the full path of the file or directory.

public string FullPath { get; protected set; }

Property Value

String

The complete absolute path to the storage object.

Remarks

This property is automatically updated when the storage object is moved or renamed through the Changed event.


IsDisposed

Gets a value indicating whether this storage object has been disposed.

public bool IsDisposed { get; }

Property Value

Boolean

true if the object has been disposed; otherwise, false.

Remarks

Use this property to check the disposal state before performing operations. Most methods will throw an ObjectDisposedException if called after disposal.


StateLock

Gets the internal lock object used to synchronize access to the state of this storage object.

public Lock StateLock { get; }

Property Value

Lock

A lock object for thread-safe state management.

Remarks

Use this lock to ensure thread-safe access to the storage object's state in derived classes.


Event Details

Changed

Occurs when the storage content changes.

public event EventHandler<StorageChangedEventArgs>? Changed

Event Type

EventHandler<StorageChangedEventArgs>

Remarks

This event is raised whenever the storage object is modified, moved, or deleted. When a deletion is detected, the object automatically disposes itself. Subscribers can use this event to track changes and respond accordingly.


Method Details

Dispose()

Releases all resources used by the current instance of the class.

public virtual void Dispose()

Remarks

Call this method when you are finished using the object to release any resources it is holding. After calling Dispose, the object should not be used. This method can be overridden in a derived class to release additional resources.


GetBufferSize()

Calculates the recommended buffer size based on the current storage information.

public int GetBufferSize()

Returns

Int32

An integer representing the recommended buffer size in bytes, ranging from 1 KB to 16 MB.

Exceptions

InvalidOperationException

Thrown if storage information is not initialized.

Remarks

This method provides an optimal buffer size for I/O operations based on the storage object's size. The buffer size is calculated to aim for approximately 100 chunks, with a minimum of 1 KB and a maximum of 16 MB.


ThrowIfDisposed()

Throws an ObjectDisposedException if this storage object has been disposed.

public void ThrowIfDisposed()

Exceptions

ObjectDisposedException

Thrown if the object has already been disposed.

Remarks

This method is typically called at the beginning of public methods to ensure the object is in a valid state before performing operations.


ToString()

Returns a string representation of the storage object.

public override string ToString()

Returns

String

A string containing the storage object's information, or a message indicating information is not available.


GetValidPath(String)

Validates the specified path and returns its absolute form if it meets the required criteria.

protected virtual string GetValidPath(string path)

Parameters

path String

The file system path to validate. Cannot be null, empty, or consist only of white-space characters, and must not contain invalid path characters.

Returns

String

The absolute path corresponding to the specified path if it passes validation.

Exceptions

ArgumentException

Thrown if the path is null, empty, consists only of white-space characters, or contains invalid path characters.

Remarks

Use this method to ensure that a path is valid and appropriate for the intended file or directory operation before proceeding. The method can be overridden in derived classes to provide additional validation logic.


WaitForFileAvailableAsync(String, Int32, Int32, CancellationToken)

Asynchronously waits until the specified file becomes available for exclusive read/write access, or until the operation times out.

protected static Task<bool> WaitForFileAvailableAsync(
    string filePath,
    int timeoutMilliseconds = 10000,
    int checkIntervalMilliseconds = 200,
    CancellationToken cancellationToken = default
)

Parameters

filePath String

The full path of the file to check for availability. Cannot be null or empty.

timeoutMilliseconds Int32

The maximum time, in milliseconds, to wait for the file to become available. Specify 0 or a negative value to wait indefinitely. The default is 10,000 milliseconds (10 seconds).

checkIntervalMilliseconds Int32

The interval, in milliseconds, between successive checks for file availability. The default is 200 milliseconds.

cancellationToken CancellationToken

A cancellation token that can be used to cancel the wait operation.

Returns

Task<Boolean>

A task that represents the asynchronous operation. The task result is true if the file became available within the specified timeout; otherwise, false.

Exceptions

ArgumentException

Thrown if filePath is null or empty.

Remarks

This method repeatedly attempts to open the file with exclusive access to determine its availability. If the file does not exist or remains locked by another process, the method waits and retries until the timeout is reached or the operation is canceled. The method is thread-safe and can be used to coordinate access to files shared between processes.


WaitForFileAvailable(String, Int32, Int32)

Waits for a file to become available for access within a specified timeout period.

protected static bool WaitForFileAvailable(
    string filePath,
    int timeoutMilliseconds = 10000,
    int checkIntervalMilliseconds = 200
)

Parameters

filePath String

The full path of the file to check for availability. Cannot be null or empty.

timeoutMilliseconds Int32

The maximum amount of time, in milliseconds, to wait for the file to become available. Must be greater than zero. The default is 10,000 milliseconds.

checkIntervalMilliseconds Int32

The interval, in milliseconds, between availability checks. Must be greater than zero. The default is 200 milliseconds.

Returns

Boolean

true if the file becomes available within the specified timeout period; otherwise, false.

Remarks

This method blocks the calling thread until the file is available or the timeout elapses. Use this method when synchronous waiting is required. For asynchronous scenarios, use WaitForFileAvailableAsync.


WaitForDirectoryAvailableAsync(String, Int32, Int32, CancellationToken)

Asynchronously waits until the specified directory becomes available for access or until the operation times out.

protected static Task<bool> WaitForDirectoryAvailableAsync(
    string dirPath,
    int timeoutMilliseconds = 10000,
    int checkIntervalMilliseconds = 200,
    CancellationToken cancellationToken = default
)

Parameters

dirPath String

The full path of the directory to check for availability. Cannot be null or empty.

timeoutMilliseconds Int32

The maximum time, in milliseconds, to wait for the directory to become available. Specify 0 for an infinite timeout. The default is 10,000 milliseconds.

checkIntervalMilliseconds Int32

The interval, in milliseconds, between successive checks for directory availability. The default is 200 milliseconds.

cancellationToken CancellationToken

A cancellation token that can be used to cancel the wait operation.

Returns

Task<Boolean>

A task that represents the asynchronous operation. The task result is true if the directory became available within the specified timeout; otherwise, false.

Exceptions

ArgumentException

Thrown if dirPath is null or empty.

Remarks

This method checks for both the existence of the directory and the ability to access it. On Windows, it attempts to open a handle to the directory; on other platforms, it tries to enumerate files within the directory. The method periodically checks availability until the directory is accessible, the timeout elapses, or the operation is canceled.


WaitForDirectoryAvailable(String, Int32, Int32)

Waits for the specified directory to become available within a given timeout period.

protected static bool WaitForDirectoryAvailable(
    string dirPath,
    int timeoutMilliseconds = 10000,
    int checkIntervalMilliseconds = 200
)

Parameters

dirPath String

The full path of the directory to check for availability. Cannot be null or empty.

timeoutMilliseconds Int32

The maximum amount of time, in milliseconds, to wait for the directory to become available. Must be greater than zero. The default is 10,000 milliseconds.

checkIntervalMilliseconds Int32

The interval, in milliseconds, between availability checks. Must be greater than zero. The default is 200 milliseconds.

Returns

Boolean

true if the directory becomes available within the specified timeout period; otherwise, false.

Remarks

This method blocks the calling thread until the directory is available or the timeout elapses. Use this method when synchronous waiting is required; for asynchronous scenarios, use WaitForDirectoryAvailableAsync.


Examples

Deriving from StorageObject

The following example demonstrates how to create a custom storage class:

using Rheo.Storage.Core;
using Rheo.Storage.Contracts;
using Rheo.Storage.Information;

public class CustomStorageObject : StorageObject
{
    private FileInformation _info;

    public CustomStorageObject(string path) : base(path, validated: false)
    {
        _info = new FileInformation(path);
    }

    public override IStorageInformation Information 
    { 
        get => _info; 
        protected set => _info = (FileInformation)value; 
    }

    public override string Name => Path.GetFileName(FullPath);
}

Using Thread-Safe State Access

The following example shows how to use StateLock for thread-safe operations:

using Rheo.Storage;

using var file = new FileObject(@"C:\Documents\file.txt");

// Thread-safe state access
lock (file.StateLock)
{
    Console.WriteLine($"Current path: {file.FullPath}");
    Console.WriteLine($"Size: {file.Information.Size}");
}

Waiting for File Availability

The following example demonstrates waiting for a file to become available:

using Rheo.Storage.Core;

public class MyStorageHandler : StorageObject
{
    public MyStorageHandler(string path) : base(path, false) { }

    public async Task ProcessFileAsync(string filePath)
    {
        // Wait up to 30 seconds for the file to become available
        bool isAvailable = await WaitForFileAvailableAsync(
            filePath, 
            timeoutMilliseconds: 30000,
            checkIntervalMilliseconds: 500
        );

        if (isAvailable)
        {
            Console.WriteLine("File is now available for processing.");
            // Process the file
        }
        else
        {
            Console.WriteLine("Timeout: File is still locked.");
        }
    }

    // Required abstract members
    public override IStorageInformation Information { get; protected set; }
    public override string Name => Path.GetFileName(FullPath);
}

Handling Change Notifications

The following example shows how to respond to storage changes:

using Rheo.Storage;

using var file = new FileObject(@"C:\Documents\file.txt");

file.Changed += (sender, e) =>
{
    Console.WriteLine($"Change detected: {e.ChangeType}");
    
    if (e.NewInfo != null)
    {
        Console.WriteLine($"New path: {e.NewInfo.AbsolutePath}");
        Console.WriteLine($"New size: {e.NewInfo.Size}");
    }
};

// Perform operations that trigger changes
file.Move(@"C:\Documents\renamed.txt");

Path Validation

The following example demonstrates custom path validation:

using Rheo.Storage.Core;
using Rheo.Storage.Contracts;

public class RestrictedStorageObject : StorageObject
{
    private readonly string _allowedDirectory;

    public RestrictedStorageObject(string path, string allowedDirectory) 
        : base(path, validated: false)
    {
        _allowedDirectory = allowedDirectory;
    }

    protected override string GetValidPath(string path)
    {
        // Call base validation first
        string validPath = base.GetValidPath(path);

        // Add custom validation
        if (!validPath.StartsWith(_allowedDirectory, StringComparison.OrdinalIgnoreCase))
        {
            throw new ArgumentException(
                $"Path must be within {_allowedDirectory}", 
                nameof(path)
            );
        }

        return validPath;
    }

    // Required abstract members
    public override IStorageInformation Information { get; protected set; }
    public override string Name => Path.GetFileName(FullPath);
}

Thread Safety

The StorageObject class provides thread-safe state management through the StateLock property. The Changed event handler and internal state updates are synchronized using this lock. Derived classes should use StateLock when accessing or modifying shared state.

See Also

Clone this wiki locally