Skip to content

SyncProgress Class

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

SyncProgress<T> Class

Provides a synchronous implementation of the IProgress<T> interface that invokes a specified callback when progress is reported.

Namespace: Rheo.Storage

Assembly: Rheo.Storage.dll

Definition

public class SyncProgress<T> : IProgress<T>

Type Parameters

T

The type of progress update value.

Inheritance

Object → SyncProgress<T>

Implements

Constructors

Constructor Description
SyncProgress(Action<T>) Initializes a new instance of the SyncProgress<T> class.

Methods

Method Description
Report(T) Reports a progress update.

Remarks

SyncProgress<T> provides a synchronous alternative to the standard Progress<T> class, which posts callbacks to the synchronization context. This class invokes the callback directly on the calling thread, making it suitable for scenarios where synchronization context marshaling is not desired or when working in console applications or background threads.

Use this class when you need immediate, synchronous progress reporting without the overhead of context switching.


Constructor Details

SyncProgress(Action<T>)

Initializes a new instance of the SyncProgress<T> class.

public SyncProgress(Action<T> callback)

Parameters

callback Action<T>

The callback to invoke when progress is reported.

Exceptions

ArgumentNullException

Thrown when callback is null.


Method Details

Report(T)

Reports a progress update.

public void Report(T value)

Parameters

value T

The value of the updated progress.

Remarks

This method directly invokes the callback provided in the constructor on the calling thread. Unlike Progress<T>, there is no asynchronous posting to a synchronization context.


Examples

Basic Progress Reporting

using Rheo.Storage;

var progress = new SyncProgress<StorageProgress>(p =>
{
    Console.WriteLine($"Progress: {p.ProgressPercentage:F1}%");
});

using var file = new FileObject(@"C:\Large\file.dat");
file.Copy(@"D:\Backup\file.dat", progress, overwrite: true);

Console Application Progress

using Rheo.Storage;

// SyncProgress is ideal for console applications
var progress = new SyncProgress<StorageProgress>(p =>
{
    // Direct, synchronous callback - no context switching
    Console.Write($"\rCopying: {p.ProgressPercentage:F1}% " +
                  $"({p.BytesTransferred:N0} / {p.TotalBytes:N0} bytes)");
});

using var dir = new DirectoryObject(@"C:\Projects");
dir.Copy(@"D:\Backup\Projects", progress, overwrite: true);

Console.WriteLine("\nCopy complete!");

Comparing with Progress<T>

using Rheo.Storage;

// Progress<T> - posts to synchronization context (async)
var asyncProgress = new Progress<StorageProgress>(p =>
{
    // This may execute on a different thread
    UpdateUI(p.ProgressPercentage);
});

// SyncProgress<T> - invokes callback directly (sync)
var syncProgress = new SyncProgress<StorageProgress>(p =>
{
    // This executes on the calling thread immediately
    Console.WriteLine(p.ProgressPercentage);
});

// Use async Progress for UI applications
await UpdateUIAsync(asyncProgress);

// Use SyncProgress for console or background operations
ProcessInBackground(syncProgress);

Custom Progress Tracking

using Rheo.Storage;

class ProgressTracker
{
    private readonly List<double> _progressHistory = new();
    
    public SyncProgress<StorageProgress> CreateProgress()
    {
        return new SyncProgress<StorageProgress>(p =>
        {
            _progressHistory.Add(p.ProgressPercentage);
            
            if (p.ProgressPercentage >= 100)
            {
                PrintStatistics();
            }
        });
    }
    
    private void PrintStatistics()
    {
        Console.WriteLine($"Total updates: {_progressHistory.Count}");
        Console.WriteLine($"Average progress per update: " +
                         $"{_progressHistory.Average():F2}%");
    }
}

var tracker = new ProgressTracker();
var progress = tracker.CreateProgress();

Thread-Safe Progress Logging

using Rheo.Storage;
using System.Collections.Concurrent;

var logQueue = new ConcurrentQueue<string>();

var progress = new SyncProgress<StorageProgress>(p =>
{
    // Thread-safe logging with SyncProgress
    string logEntry = $"[{DateTime.Now:HH:mm:ss}] " +
                      $"{p.ProgressPercentage:F1}% - " +
                      $"{p.BytesPerSecond / 1024:F0} KB/s";
    
    logQueue.Enqueue(logEntry);
    Console.WriteLine(logEntry);
});

// Process multiple files in parallel
var files = new[] { "file1.dat", "file2.dat", "file3.dat" };
Parallel.ForEach(files, filePath =>
{
    using var file = new FileObject(filePath);
    file.Copy($"{filePath}.bak", progress);
});

// Write logs to file
File.WriteAllLines("progress.log", logQueue);

Thread Safety

SyncProgress<T> is thread-safe. However, the callback is invoked synchronously on the thread that calls Report, so the callback itself must be thread-safe if used in multi-threaded scenarios.

See Also

Clone this wiki locally