diff --git a/BackgroundProcessing/Core/Odin.BackgroundProcessing.csproj b/BackgroundProcessing/Core/Odin.BackgroundProcessing.csproj
index c30b3ae..54fc045 100644
--- a/BackgroundProcessing/Core/Odin.BackgroundProcessing.csproj
+++ b/BackgroundProcessing/Core/Odin.BackgroundProcessing.csproj
@@ -10,24 +10,40 @@
has static entry points to its functionality.
-
1591;1573;
-
-
-
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/Configuration/AzureBlobJson/Odin.Configuration.AzureBlobJson.csproj b/Configuration/AzureBlobJson/Odin.Configuration.AzureBlobJson.csproj
index 0a50e08..3fa86f8 100644
--- a/Configuration/AzureBlobJson/Odin.Configuration.AzureBlobJson.csproj
+++ b/Configuration/AzureBlobJson/Odin.Configuration.AzureBlobJson.csproj
@@ -13,8 +13,21 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Data/SqlScriptsRunner/Odin.Data.SqlScriptsRunner.csproj b/Data/SqlScriptsRunner/Odin.Data.SqlScriptsRunner.csproj
index b62cb6b..f11cd37 100644
--- a/Data/SqlScriptsRunner/Odin.Data.SqlScriptsRunner.csproj
+++ b/Data/SqlScriptsRunner/Odin.Data.SqlScriptsRunner.csproj
@@ -15,9 +15,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Email/Core/IEmailSender.cs b/Email/Core/IEmailSender.cs
index 06b47ca..7ae2ed4 100644
--- a/Email/Core/IEmailSender.cs
+++ b/Email/Core/IEmailSender.cs
@@ -12,7 +12,7 @@ public interface IEmailSender
///
///
/// Success and the Mailgun messageId populated in the Value of the Outcome if available.
- Task> SendEmail(IEmailMessage email);
+ Task> SendEmail(IEmailMessage email);
}
}
\ No newline at end of file
diff --git a/Email/Core/NullEmailSender.cs b/Email/Core/NullEmailSender.cs
index e4b7806..72c7106 100644
--- a/Email/Core/NullEmailSender.cs
+++ b/Email/Core/NullEmailSender.cs
@@ -12,9 +12,9 @@ public sealed class NullEmailSender : IEmailSender
///
///
///
- public async Task> SendEmail(IEmailMessage email)
+ public async Task> SendEmail(IEmailMessage email)
{
- return await Task.FromResult(ResultValue.Success("12345"));
+ return await Task.FromResult(ResultValue.Success("12345"));
}
}
}
diff --git a/Email/Core/Odin.Email.csproj b/Email/Core/Odin.Email.csproj
index 0a458fa..e15b3f2 100644
--- a/Email/Core/Odin.Email.csproj
+++ b/Email/Core/Odin.Email.csproj
@@ -14,11 +14,25 @@
1591;1573;
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Email/Mailgun/MailgunEmailSender.cs b/Email/Mailgun/MailgunEmailSender.cs
index 6f1383f..62c474b 100644
--- a/Email/Mailgun/MailgunEmailSender.cs
+++ b/Email/Mailgun/MailgunEmailSender.cs
@@ -110,7 +110,7 @@ private static ByteArrayContent ToByteArrayContent(Stream stream)
///
/// An Outcome containing the Mailgun messageId.
///
- public async Task> SendEmail(IEmailMessage email)
+ public async Task> SendEmail(IEmailMessage email)
{
Precondition.RequiresNotNull(email);
Precondition.Requires(email.To.Any(), "Mailgun requires one or more to addresses.");
@@ -182,11 +182,11 @@ private static ByteArrayContent ToByteArrayContent(Stream stream)
MailgunSendResponse? response = await responseMessage.Content.ReadFromJsonAsync();
LogSendEmailResult(email, true, LogLevel.Information, $"Sent with Mailgun reference {response?.Id}.");
- return ResultValue.Success(response?.Id);
+ return ResultValue.Success(response?.Id ?? "");
}
catch (Exception e)
{
- return ResultValue.Failure(e.ToString());
+ return ResultValue.Failure(e.ToString());
}
}
diff --git a/Email/Office365/Office365EmailSender.cs b/Email/Office365/Office365EmailSender.cs
index e8d8ad1..2028f92 100644
--- a/Email/Office365/Office365EmailSender.cs
+++ b/Email/Office365/Office365EmailSender.cs
@@ -56,7 +56,7 @@ public Office365EmailSender(Office365Options office365Options, EmailSendingOptio
const string MicrosoftGraphFileAttachmentOdataType = "#microsoft.graph.fileAttachment";
///
- public async Task> SendEmail(IEmailMessage email)
+ public async Task> SendEmail(IEmailMessage email)
{
if (email.From is null)
{
@@ -122,12 +122,12 @@ public Office365EmailSender(Office365Options office365Options, EmailSendingOptio
await _graphClient.Users[_senderUserId].SendMail.PostAsync(requestBody);
LogSendEmailResult(email, true, LogLevel.Information, $"Sent with Office365 via user {_senderUserId}");
- return ResultValue.Success("Success");
+ return ResultValue.Success("Success");
}
catch (Exception ex)
{
LogSendEmailResult(email, false, LogLevel.Error, $"Failed to send with Office365 via user {_senderUserId}", ex);
- return ResultValue.Failure("Fail: " + ex.Message);
+ return ResultValue.Failure("Fail: " + ex.Message);
}
}
diff --git a/Email/Tests/Mailgun/MailgunEmailSenderTests.cs b/Email/Tests/Mailgun/MailgunEmailSenderTests.cs
index b46d079..81caf96 100644
--- a/Email/Tests/Mailgun/MailgunEmailSenderTests.cs
+++ b/Email/Tests/Mailgun/MailgunEmailSenderTests.cs
@@ -115,7 +115,7 @@ public async Task Send_with_attachment()
VerifySuccessfulSendAndLogging(scenario, message, result);
}
- private void VerifySuccessfulSendAndLogging(MailgunEmailSenderTestBuilder scenario,EmailMessage message, ResultValue result)
+ private void VerifySuccessfulSendAndLogging(MailgunEmailSenderTestBuilder scenario,EmailMessage message, ResultValue result)
{
// Result
Assert.That(result.IsSuccess, Is.True, result.MessagesToString());
diff --git a/Logging/Core/Odin.Logging.csproj b/Logging/Core/Odin.Logging.csproj
index e7fa4b8..02c3f31 100644
--- a/Logging/Core/Odin.Logging.csproj
+++ b/Logging/Core/Odin.Logging.csproj
@@ -1,27 +1,38 @@
-
- net8.0;net9.0;net10.0
- Odin
- true
- enable
- icon.png
- README.md
- Provides ILoggerWrapper that extends .NET's ILogger of T
- with all the LogXXX(...) calls as provided by the .NET LoggerExtensions extension methods.
- The primary reason being for much more convenient assertions of logger calls compared to mocking ILogger,
- and asserting ILogger -> Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, etc...
-
-
-
+
+ net8.0;net9.0;net10.0
+ Odin
+ true
+ enable
+ icon.png
+ README.md
+ Provides ILoggerWrapper that extends .NET's ILogger of T
+ with all the LogXXX(...) calls as provided by the .NET LoggerExtensions extension methods.
+ The primary reason being for much more convenient assertions of logger calls compared to mocking ILogger,
+ and asserting ILogger -> Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, etc...
+
+
- 1591;1573;
-
-
-
-
-
-
-
-
-
+ 1591;1573;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Messaging/RabbitMq/Odin.Messaging.RabbitMq.csproj b/Messaging/RabbitMq/Odin.Messaging.RabbitMq.csproj
index 2b68de9..0120b53 100644
--- a/Messaging/RabbitMq/Odin.Messaging.RabbitMq.csproj
+++ b/Messaging/RabbitMq/Odin.Messaging.RabbitMq.csproj
@@ -13,10 +13,24 @@
CS1591
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/RemoteFiles/Core/Odin.RemoteFiles.csproj b/RemoteFiles/Core/Odin.RemoteFiles.csproj
index f414ddf..3f7edb8 100644
--- a/RemoteFiles/Core/Odin.RemoteFiles.csproj
+++ b/RemoteFiles/Core/Odin.RemoteFiles.csproj
@@ -16,10 +16,22 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/System/Activator2/Activator2.cs b/System/Activator2/Activator2.cs
index e90ccf9..b99780a 100644
--- a/System/Activator2/Activator2.cs
+++ b/System/Activator2/Activator2.cs
@@ -37,7 +37,7 @@ public static ResultValue TryCreate(string typeName, string assemblyName)
return ResultValue.Failure($"Type {typeName} is not of type {nameof(T)}");
}
- private static ResultValue CreateInstanceFailure(string typeName, string assemblyName, string? errorMessage = "")
+ private static ResultValue CreateInstanceFailure(string typeName, string assemblyName, string? errorMessage = "") where T : notnull
{
return ResultValue.Failure($"Could not create instance of type {typeName} from assembly {assemblyName}. {errorMessage}");
}
diff --git a/System/Result/MessageEx.cs b/System/Result/MessageEx.cs
index ba30c44..42ca6f7 100644
--- a/System/Result/MessageEx.cs
+++ b/System/Result/MessageEx.cs
@@ -5,7 +5,7 @@ namespace Odin.System;
///
/// Extended 'Message' including a Severity, and optional Exception.
///
-public record MessageEx
+public class MessageEx
{
///
/// Message content. Can be null.
diff --git a/System/Result/Odin.System.Result.csproj b/System/Result/Odin.System.Result.csproj
index 1b75e62..c2ccee8 100644
--- a/System/Result/Odin.System.Result.csproj
+++ b/System/Result/Odin.System.Result.csproj
@@ -15,9 +15,19 @@
1591;1573;
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/System/Result/Result.cs b/System/Result/Result.cs
index 0c63deb..4f22e38 100644
--- a/System/Result/Result.cs
+++ b/System/Result/Result.cs
@@ -5,7 +5,7 @@
/// Represents the outcome of an operation that was successful or failed,
/// together with a list of Messages.
///
- public record Result : Result
+ public class Result : Result
{
///
public Result()
diff --git a/System/Result/ResultEx.cs b/System/Result/ResultEx.cs
index 3c2691b..58536a8 100644
--- a/System/Result/ResultEx.cs
+++ b/System/Result/ResultEx.cs
@@ -7,7 +7,7 @@ namespace Odin.System
/// Like Result, but with a list of Messages of type ResultMessage2
/// which includes a Severity, a Message and optionally an Exception.
///
- public record ResultEx : Result
+ public class ResultEx : Result
{
///
public ResultEx()
diff --git a/System/Result/ResultOfTMessage.cs b/System/Result/ResultOfTMessage.cs
index 5fe8ee4..a23574d 100644
--- a/System/Result/ResultOfTMessage.cs
+++ b/System/Result/ResultOfTMessage.cs
@@ -5,13 +5,13 @@
/// with a list of messages of type TMessage.
///
///
- public record Result where TMessage : class
+ public class Result where TMessage : class
{
///
/// True if successful
///
public bool IsSuccess { get; init; }
-
+
///
/// Messages list
///
@@ -28,12 +28,12 @@ public IReadOnlyList Messages
_messages ??= new List();
return _messages;
}
- init // For deserialisation
+ init // For deserialisation
{
_messages = value.ToList();
}
}
-
+
///
/// All messages flattened into 1 message.
/// Assumes a decent implementation of TMessage.ToString()
@@ -44,6 +44,7 @@ public string MessagesToString(string separator = " | ")
{
return string.Empty;
}
+
return string.Join(separator, _messages.Select(c => c.ToString()));
}
@@ -55,7 +56,7 @@ public Result()
{
IsSuccess = false;
}
-
+
///
/// Result constructor.
///
@@ -104,7 +105,7 @@ public static Result Failure(IEnumerable messages)
{
return new Result(false, messages);
}
-
+
///
/// Success.
///
@@ -113,7 +114,7 @@ public static Result Success()
{
return new Result(true);
}
-
+
///
/// Success, optionally including a message
///
diff --git a/System/Result/ResultValue.cs b/System/Result/ResultValue.cs
index 3225b24..ac04b5f 100644
--- a/System/Result/ResultValue.cs
+++ b/System/Result/ResultValue.cs
@@ -1,12 +1,12 @@
namespace Odin.System
{
///
- /// Represents the success or failure of an operation that returns a Value\Result on success,
+ /// Represents the success or failure of an operation that returns a non-null Value\Result on success,
/// and list of string messages.
///
///
/// To be renamed to ResultValue of TValue
- public record ResultValue : ResultValue
+ public class ResultValue : ResultValue where TValue : notnull
{
///
/// Parameterless constructor for serialization.
@@ -25,6 +25,7 @@ public ResultValue()
public ResultValue(bool isSuccess, TValue? value, IEnumerable? messages)
{
Precondition.Requires(!(value == null && isSuccess), "Value is required for a successful result.");
+ IsSuccess = isSuccess;
Value = value;
_messages = messages?.ToList();
}
@@ -100,5 +101,22 @@ public ResultValue(bool isSuccess, TValue? value, string? message = null)
{
return new ResultValue(true, value, messages);
}
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override ResultValue ToFailedResult()
+ {
+ if (IsSuccess)
+ {
+ throw new ArgumentException($"Cannot convert a successful result of type {GetType().FullName} " +
+ $"to a failed result of type {typeof(ResultValue).FullName}.");
+ }
+
+ return ResultValue.Failure(Messages);
+ }
}
}
\ No newline at end of file
diff --git a/System/Result/ResultValueEx.cs b/System/Result/ResultValueEx.cs
index 06f8bf8..785544a 100644
--- a/System/Result/ResultValueEx.cs
+++ b/System/Result/ResultValueEx.cs
@@ -7,7 +7,7 @@
///
///
/// To be renamed to ResultValueEx of TValue
- public record ResultValueEx : ResultValue
+ public class ResultValueEx : ResultValue where TValue : notnull
{
///
/// Parameterless constructor for serialization.
@@ -26,6 +26,7 @@ public ResultValueEx()
public ResultValueEx(bool isSuccess, TValue? value, IEnumerable? messages)
{
Precondition.Requires(!(value == null && isSuccess), "Value is required for a successful result.");
+ IsSuccess = isSuccess;
Value = value;
_messages = messages?.ToList();
}
diff --git a/System/Result/ResultValueNullable.cs b/System/Result/ResultValueNullable.cs
new file mode 100644
index 0000000..ec9aa3a
--- /dev/null
+++ b/System/Result/ResultValueNullable.cs
@@ -0,0 +1,120 @@
+namespace Odin.System;
+
+///
+/// Represents the success or failure of an operation that returns a possibly null Value\Result on success,
+/// and list of string messages.
+///
+///
+public class ResultValueNullable : ResultValueNullable
+{
+ ///
+ /// Parameterless constructor for serialization.
+ ///
+ public ResultValueNullable()
+ {
+ IsSuccess = false;
+ }
+
+ ///
+ /// Default constructor.
+ ///
+ /// true or false
+ /// Required if successful
+ /// Optional, but good practice is to provide messages for failed results.
+ public ResultValueNullable(bool isSuccess, TValue? value, IEnumerable? messages)
+ {
+ IsSuccess = isSuccess;
+ Value = value;
+ _messages = messages?.ToList();
+ }
+
+ ///
+ /// Default constructor.
+ ///
+ /// true or false
+ /// Required if successful
+ /// Optional, but good practice is to provide messages for failed results.
+ public ResultValueNullable(bool isSuccess, TValue? value, string? message = null)
+ {
+ IsSuccess = isSuccess;
+ Value = value;
+ _messages = message != null ? [message] : null;
+ }
+
+ ///
+ /// Success.
+ ///
+ /// Normally included as best practice for failed operations, but not mandatory.
+ /// Normally null\default for a failure, but not necessarily.
+ ///
+ public new static ResultValueNullable Failure(IEnumerable messages, TValue? value = default(TValue) )
+ {
+ Precondition.RequiresNotNull(messages);
+ List list = messages.ToList();
+ Precondition.Requires(list.Any(s => !string.IsNullOrWhiteSpace(s)),"At least 1 message is required.");
+ return new ResultValueNullable(false, value, list);
+ }
+
+ ///
+ /// Success.
+ ///
+ /// Required for failed operations.
+ /// Normally null\default for a failure, but not necessarily.
+ ///
+ public new static ResultValueNullable Failure(string message, TValue? value = default(TValue) )
+ {
+ Precondition.Requires(!string.IsNullOrWhiteSpace(message), $"{nameof(message)} is required.");
+ return new ResultValueNullable(false, value, new List() { message });
+ }
+
+ ///
+ /// Creates a successful Result with Value set.
+ ///
+ ///
+ ///
+ public new static ResultValueNullable Success(TValue value)
+ {
+ return new ResultValueNullable(true, value, null as string);
+ }
+
+ ///
+ /// Creates a successful Result with Value set and a single Message.
+ ///
+ ///
+ ///
+ ///
+ public new static ResultValueNullable Success(TValue value, string? message)
+ {
+ return new ResultValueNullable(true, value, message);
+ }
+
+ ///
+ /// Creates a successful Result with Value set, and several Messages.
+ ///
+ ///
+ ///
+ ///
+ public new static ResultValueNullable Success(TValue value, IEnumerable messages)
+ {
+ return new ResultValueNullable(true, value, messages);
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public override ResultValueNullable ToFailedResult()
+ {
+ if (IsSuccess)
+ {
+ throw new ArgumentException($"Cannot convert a successful result of type {GetType().FullName} " +
+ $"to a failed result of type {typeof(ResultValue).FullName}.");
+ }
+
+ return ResultValueNullable.Failure(Messages);
+ }
+
+
+}
\ No newline at end of file
diff --git a/System/Result/ResultValueNullableOfTMessage.cs b/System/Result/ResultValueNullableOfTMessage.cs
new file mode 100644
index 0000000..1e2685f
--- /dev/null
+++ b/System/Result/ResultValueNullableOfTMessage.cs
@@ -0,0 +1,180 @@
+namespace Odin.System;
+
+///
+/// Represents the success or failure of an operation that returns a Value\Result on success,
+/// and list of messages, of type TMessage.
+///
+///
+///
+public class ResultValueNullable where TMessage : class
+{
+ ///
+ /// True if successful
+ ///
+ public bool IsSuccess { get; init; }
+
+ ///
+ /// Value may or may not be set when successful.
+ /// Value is null when Success is false.
+ ///
+ public TValue? Value { get; init; }
+
+ ///
+ /// Messages list
+ ///
+ // ReSharper disable once InconsistentNaming
+ protected List? _messages;
+
+ ///
+ /// Messages
+ ///
+ public IReadOnlyList Messages
+ {
+ get
+ {
+ _messages ??= new List();
+ return _messages;
+ }
+ init // For deserialisation
+ {
+ _messages = value.ToList();
+ }
+ }
+
+ ///
+ /// All messages flattened into 1 message.
+ /// Assumes a decent implementation of TMessage.ToString()
+ ///
+ public string MessagesToString(string separator = " | ")
+ {
+ if (_messages == null || _messages.Count == 0)
+ {
+ return string.Empty;
+ }
+
+ return string.Join(separator, _messages.Select(c => c.ToString()));
+ }
+
+
+ ///
+ /// Parameterless constructor for serialisation, etc.
+ ///
+ public ResultValueNullable()
+ {
+ Value = default(TValue);
+ }
+
+ ///
+ /// Default constructor.
+ ///
+ /// true or false
+ /// Required if successful
+ /// Optional, but good practice is to provide messages for failed results.
+ protected ResultValueNullable(bool success, TValue? value, IEnumerable? messages)
+ {
+ IsSuccess = success;
+ Value = value;
+ _messages = messages?.ToList();
+ }
+
+ ///
+ /// Default constructor.
+ ///
+ /// true or false
+ /// Required if successful
+ /// Optional, but good practice is to provide messages for failed results.
+ protected ResultValueNullable(bool success, TValue? value, TMessage? message = null)
+ {
+ IsSuccess = success;
+ Value = value;
+ _messages = message != null ? [message] : null;
+ }
+
+ ///
+ /// Success.
+ ///
+ /// Required.
+ /// Not normally used for successful operations, but can be for informational purposes.
+ ///
+ public static ResultValueNullable Success(TValue value, IEnumerable? messages)
+ {
+ return new ResultValueNullable(true, value, messages);
+ }
+
+ ///
+ /// Creates a successful Result with Value set.
+ ///
+ /// Required.
+ ///
+ public static ResultValueNullable Success(TValue value)
+ {
+ return new ResultValueNullable(true, value, null as TMessage);
+ }
+
+ ///
+ /// Creates a successful Result with Value set, and 1 Message item.
+ ///
+ /// Required.
+ /// Not normally used for successful operations, but can be for informational purposes.
+ ///
+ public static ResultValueNullable Success(TValue value, TMessage? message)
+ {
+ return new ResultValueNullable(true, value, message);
+ }
+
+ ///
+ /// Creates a successful Result with Value set, and several Messages.
+ ///
+ /// At least 1 not null message is required.
+ /// Normally null\default for a failure, but not necessarily.
+ ///
+ public static ResultValueNullable Failure(IEnumerable messages, TValue? value = default(TValue))
+ {
+ Precondition.RequiresNotNull(messages);
+ List messagesList = messages.ToList();
+ Precondition.Requires(messagesList.Any(m => m != null!), "At least 1 message is required.");
+ return new ResultValueNullable(false, value, messagesList);
+ }
+
+ ///
+ /// Success.
+ ///
+ /// Required for failed operations.
+ /// Normally null\default for a failure, but not necessarily.
+ ///
+ public static ResultValueNullable Failure(TMessage message, TValue? value = default(TValue))
+ {
+ Precondition.RequiresNotNull(message);
+ return new ResultValueNullable(false, value, new List() { message });
+ }
+
+
+ ///
+ ///
+ ///
+ ///
+ public Result ToResult()
+ {
+ return IsSuccess
+ ? Result.Success()
+ : Result.Failure(Messages.Select(m =>
+ m.ToString()
+ ?? $"No string representation of message of type {typeof(TMessage).FullName}"));
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual ResultValueNullable ToFailedResult() where TOtherValue : notnull
+ {
+ if (IsSuccess)
+ {
+ throw new ArgumentException($"Cannot convert a successful result of type {GetType().FullName} " +
+ $"to a failed result of type {typeof(ResultValueNullable).FullName}.");
+ }
+
+ return ResultValueNullable.Failure(Messages);
+ }
+}
\ No newline at end of file
diff --git a/System/Result/ResultValueOfTMessage.cs b/System/Result/ResultValueOfTMessage.cs
index 5925d43..edcb091 100644
--- a/System/Result/ResultValueOfTMessage.cs
+++ b/System/Result/ResultValueOfTMessage.cs
@@ -8,20 +8,20 @@ namespace Odin.System
///
///
///
- public record ResultValue where TMessage : class
+ public class ResultValue where TMessage : class where TValue : notnull
{
///
/// True if successful
///
[MemberNotNullWhen(true, nameof(Value))]
public bool IsSuccess { get; init; }
-
+
///
- /// Value is typically set when Success is True.
+ /// Value is always set when Success is True.
/// Value is null when Success is false.
///
public TValue? Value { get; init; }
-
+
///
/// Messages list
///
@@ -38,12 +38,12 @@ public IReadOnlyList Messages
_messages ??= new List();
return _messages;
}
- init // For deserialisation
+ init // For deserialisation
{
_messages = value.ToList();
}
}
-
+
///
/// All messages flattened into 1 message.
/// Assumes a decent implementation of TMessage.ToString()
@@ -54,6 +54,7 @@ public string MessagesToString(string separator = " | ")
{
return string.Empty;
}
+
return string.Join(separator, _messages.Select(c => c.ToString()));
}
@@ -75,6 +76,7 @@ public ResultValue()
protected ResultValue(bool success, TValue? value, IEnumerable? messages)
{
Precondition.Requires(!(value == null && success), "Value is required for a successful result.");
+ IsSuccess = success;
Value = value;
_messages = messages?.ToList();
}
@@ -88,6 +90,7 @@ protected ResultValue(bool success, TValue? value, IEnumerable? messag
protected ResultValue(bool success, TValue? value, TMessage? message = null)
{
Precondition.Requires(!(value == null && success), "Value is required for a successful result.");
+ IsSuccess = success;
Value = value;
_messages = message != null ? [message] : null;
}
@@ -101,7 +104,7 @@ protected ResultValue(bool success, TValue? value, TMessage? message = null)
public static ResultValue Success(TValue value, IEnumerable? messages)
{
Precondition.RequiresNotNull(value);
- return new ResultValue(true, value, messages);
+ return new ResultValue(true, value, messages);
}
///
@@ -114,7 +117,7 @@ public static ResultValue Success(TValue value)
Precondition.RequiresNotNull(value);
return new ResultValue(true, value, null as TMessage);
}
-
+
///
/// Creates a successful Result with Value set, and 1 Message item.
///
@@ -133,7 +136,7 @@ public static ResultValue Success(TValue value, TMessage? mess
/// At least 1 not null message is required.
/// Normally null\default for a failure, but not necessarily.
///
- public static ResultValue Failure(IEnumerable messages, TValue? value = default(TValue) )
+ public static ResultValue Failure(IEnumerable messages, TValue? value = default(TValue))
{
Precondition.RequiresNotNull(messages);
List messagesList = messages.ToList();
@@ -147,10 +150,42 @@ public static ResultValue Success(TValue value, TMessage? mess
/// Required for failed operations.
/// Normally null\default for a failure, but not necessarily.
///
- public static ResultValue Failure(TMessage message, TValue? value = default(TValue) )
+ public static ResultValue Failure(TMessage message, TValue? value = default(TValue))
{
Precondition.RequiresNotNull(message);
return new ResultValue(false, value, new List() { message });
}
+
+
+ ///
+ ///
+ ///
+ ///
+ public Result ToResult()
+ {
+ return IsSuccess
+ ? Result.Success()
+ : Result.Failure(Messages.Select(m =>
+ m.ToString()
+ ?? $"No string representation of message of type {typeof(TMessage).FullName}"));
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public virtual ResultValue ToFailedResult() where TOtherValue : notnull
+ {
+ if (IsSuccess)
+ {
+ throw new ArgumentException($"Cannot convert a successful result of type {GetType().FullName} " +
+ $"to a failed result of type {typeof(ResultValue).FullName}.");
+ }
+
+ return ResultValue.Failure(Messages);
+ }
+
+
}
}
\ No newline at end of file
diff --git a/Utility/VaryingValues/Odin.Utility.VaryingValues.csproj b/Utility/VaryingValues/Odin.Utility.VaryingValues.csproj
index deb20f1..c6dc8da 100644
--- a/Utility/VaryingValues/Odin.Utility.VaryingValues.csproj
+++ b/Utility/VaryingValues/Odin.Utility.VaryingValues.csproj
@@ -14,10 +14,22 @@
1591;1573;
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+