Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 208 additions & 0 deletions getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
# Getting Started

This guide will help you get up and running with the Try Pattern library in just a few minutes.

## Installation

### NuGet Package

Install the Try Pattern library via NuGet Package Manager:

```bash
dotnet add package Wolfgang.TryPattern
```

Or using the Package Manager Console:

```powershell
Install-Package Wolfgang.TryPattern
```

### Manual Installation

Alternatively, you can clone the repository and reference the project directly:

```bash
git clone https://github.com/Chris-Wolfgang/Try-Pattern.git
```

## Basic Usage

### 1. Using Try with Async Operations

The most common use case is wrapping async operations that may fail:

```csharp
using Wolfgang.TryPattern;

// Reading a file that might not exist
var result = await Try.RunAsync(() => File.ReadAllTextAsync("data.txt"));

if (result.Succeeded)
{
Console.WriteLine($"File content: {result.Value}");
}
else
{
Console.WriteLine($"Failed to read file: {result.ErrorMessage}");
}
```

### 2. Using Try with Synchronous Operations

You can also use the Try Pattern with synchronous operations:

```csharp
using Wolfgang.TryPattern;

// Parsing a JSON file
var result = Try.Run(() => JsonSerializer.Deserialize<MyData>(jsonString));

if (result.Succeeded)
{
ProcessData(result.Value);
}
else
{
LogError(result.ErrorMessage);
}
```

### 3. Using Result for Custom Methods

Use `Result` and `Result<T>` as return types for your own methods:

```csharp
using Wolfgang.TryPattern;

public Result ValidateEmail(string email)
{
if (string.IsNullOrWhiteSpace(email))
{
return Result.Failure("Email cannot be empty");
}

if (!email.Contains("@"))
{
return Result.Failure("Email must contain @");
}

return Result.Success();
}

public Result<User> GetUser(int userId)
{
var user = database.FindUser(userId);

if (user == null)
{
return Result<User>.Failure("User not found");
}

return Result<User>.Success(user);
}
```

## Common Patterns

### Pattern 1: File Operations

```csharp
var result = await Try.RunAsync(() => File.ReadAllTextAsync(filePath));
if (!result.Succeeded)
{
// Handle failure - file doesn't exist, no permissions, etc.
return;
}

// Process the file content
var content = result.Value;
```

### Pattern 2: HTTP Requests

```csharp
public async Task<Result<string>> FetchDataAsync(string url)
{
using var response = await httpClient.GetAsync(url);

if (!response.IsSuccessStatusCode)
{
return Result<string>.Failure($"HTTP {response.StatusCode}");
}

var content = await response.Content.ReadAsStringAsync();
Comment on lines +127 to +134
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The async call to httpClient.GetAsync(url) should use ConfigureAwait(false) to avoid potential deadlocks in synchronization contexts. According to the project's coding guidelines, async methods should use ConfigureAwait(false).

Change to:

using var response = await httpClient.GetAsync(url).ConfigureAwait(false);
Suggested change
using var response = await httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode)
{
return Result<string>.Failure($"HTTP {response.StatusCode}");
}
var content = await response.Content.ReadAsStringAsync();
using var response = await httpClient.GetAsync(url).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
{
return Result<string>.Failure($"HTTP {response.StatusCode}");
}
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The async call to response.Content.ReadAsStringAsync() should use ConfigureAwait(false) to avoid potential deadlocks in synchronization contexts. According to the project's coding guidelines, async methods should use ConfigureAwait(false).

Change to:

var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
Suggested change
var content = await response.Content.ReadAsStringAsync();
var content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

Copilot uses AI. Check for mistakes.
return Result<string>.Success(content);
}
```

### Pattern 3: Database Operations

```csharp
public async Task<Result> SaveUserAsync(User user)
{
if (user == null)
{
throw new ArgumentNullException(nameof(user)); // Programming error
}

var saveResult = await Try.RunAsync(() => database.SaveAsync(user));

if (!saveResult.Succeeded)
{
return Result.Failure("Failed to save user to database");
}

return Result.Success();
}
```

## Examples

The repository includes several example projects demonstrating the Try Pattern in different scenarios:

- **C# .NET 8 Example**: Modern C# with latest features
- **C# .NET 4.6.2 Example**: .NET Framework support
- **F# Examples**: Functional programming approach (.NET 4.6.2 and .NET 8)
- **VB.NET Examples**: Visual Basic support (.NET 4.6.2 and .NET 8)

The library itself supports .NET Framework 4.6.2, .NET Standard 2.0, .NET 8.0, and .NET 10.0.

You can find these examples in the `examples` folder of the repository.

## API Reference

### Try Class

- `Try.Run<T>(Func<T> func)`: Execute a synchronous function
- `Try.RunAsync<T>(Func<Task<T>> func)`: Execute an async function
- `Try.Run(Action action)`: Execute a synchronous action
- `Try.RunAsync(Func<Task> func)`: Execute an async action

### Result Class

- `Result.Success()`: Create a successful result
- `Result.Failure(string message)`: Create a failed result
- `Succeeded`: Boolean indicating success
- `ErrorMessage`: Error message when failed

### Result<T> Class

- `Result<T>.Success(T value)`: Create a successful result with a value
- `Result<T>.Failure(string message)`: Create a failed result
- `Succeeded`: Boolean indicating success
- `Value`: The returned value when successful
- `ErrorMessage`: Error message when failed

## Next Steps

- Read the [Introduction](introduction.md) for a deeper understanding of the Try Pattern
- Check out the examples in the `examples` folder
- Review the [readme.md](readme.md) for more detailed examples
- Explore the source code in the `src/Wolfgang.TryPattern` folder

## Need Help?

- Open an issue on [GitHub](https://github.com/Chris-Wolfgang/Try-Pattern/issues)
- Check the [Contributing Guide](CONTRIBUTING.md) if you want to contribute
- Review the [Code of Conduct](CODE_OF_CONDUCT.md)
85 changes: 85 additions & 0 deletions introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Introduction

Welcome to the Try Pattern library! This library provides a simple and effective way to implement the Try Pattern in your C# applications.

## What is the Try Pattern?

The Try Pattern is a design pattern where code execution returns success/failure status without exposing detailed exception information to the caller. This is particularly useful when:

- The caller only needs to know if an operation succeeded or failed
- The specific reason for failure is not relevant to the caller
- You want to avoid using exceptions for control flow

## Why Use the Try Pattern?

### Benefits

1. **Simplified Error Handling**: No need to catch and handle specific exceptions
2. **Cleaner Code**: Reduces try-catch blocks throughout your codebase
3. **Better Performance**: Avoids the overhead of exception creation for expected failures
4. **Clearer Intent**: Makes it explicit that an operation may fail

### Real-World Examples

You're already familiar with the Try Pattern from .NET's built-in types:
- `int.TryParse(string, out int)`
- `DateTime.TryParse(string, out DateTime)`
- `Dictionary<TKey, TValue>.TryGetValue(TKey, out TValue)`

## How This Library Helps

This library extends the Try Pattern to any operation by providing:

1. **`Try` Class**: Static helper methods to execute operations and handle exceptions
2. **`Result` Type**: Represents the outcome of an operation without a return value
3. **`Result<T>` Type**: Represents the outcome of an operation that returns a value

### Compatibility

The library supports .NET Framework 4.6.2 through .NET 10.0, including:
- .NET Framework 4.6.2 and later
- .NET Standard 2.0
- .NET 8.0
- .NET 10.0

## Quick Example

```csharp
// Without Try Pattern - traditional approach
try
{
var content = await File.ReadAllTextAsync("config.json");
ProcessConfig(content);
}
catch (Exception ex)
{
Console.WriteLine("Error reading config: " + ex.Message);
}

// With Try Pattern - simplified approach
var result = await Try.RunAsync(() => File.ReadAllTextAsync("config.json"));
if (result.Succeeded)
{
ProcessConfig(result.Value);
}
else
{
Console.WriteLine("Error reading config: " + result.ErrorMessage);
}
```

## When to Use the Try Pattern

**Use the Try Pattern when:**
- Operations may fail in expected ways (file not found, network timeout, etc.)
- The caller only needs success/failure information
- You want to avoid exception-based control flow

**Don't use the Try Pattern when:**
- You need specific exception details for different error handling
- The failure is truly exceptional and should propagate up the call stack
- You're dealing with programming errors (null arguments, invalid state)

## Next Steps

Ready to get started? Check out the [Getting Started](getting-started.md) guide to learn how to install and use the library in your projects.
Loading