Reputation: 23284
I have a class that indicates if a call to a method was successful (with a value) or has an error.
internal sealed class ValueOrError<TValue>
{
public bool IsError => _error is not null;
public bool IsSuccess => !IsError;
private TValue? _value;
private Error? _error;
private ValueOrError() { }
public TValue? Value =>
_error is null
? _value
: throw new InvalidOperationException("Is an error type");
public Error Error => _error ?? throw new InvalidOperationException("Not an error type");
public static ValueOrError<TValue> FromValue(TValue? result) =>
new ValueOrError<TValue> { _value = result };
public static ValueOrError<TValue> FromError(Error error) =>
new ValueOrError<TValue> { _error = error ?? throw new ArgumentNullException(nameof(error)) };
public static implicit operator ValueOrError<TValue>(TValue value) => ValueOrError<TValue>.FromValue(value);
public static implicit operator ValueOrError<TValue>(Error error) => ValueOrError<TValue>.FromError(error);
}
I can cast implicitly just fine unless TValue
is an IEnumerable<T>
.
// Works
ValueOrError<int> x = 1;
// Fails
ValueOrError<IEnumerable<int>> y = Enumerable.Empty<int>();
Cannot implicitly convert type 'System.Collections.Generic.IEnumerable' to 'AppLayer.ValueOrError'
However, I can create a result of that type "the long way"
c# // Works ValueOrError<IEnumerable<int>>.FromValue(Enumerable.Empty<int>());
In case it is useful, the source for Error
is
public class Error
{
public string Message { get; }
[JsonConstructor]
public Error(string message)
{
Message = message ?? throw new ArgumentNullException(nameof(message));
}
}
Upvotes: 4
Views: 242
Reputation: 1276
If you look at the C# specifications about User-defined conversions:
One of the prerequisites to use implicit or explicit operators is that
Neither S₀ nor T₀ is an interface_type.
So, if you really want to use implicit conversion, you'll have to convert your interface reference into a class reference (by calling .ToArray()
for example).
Or you can create a static class to take advantage of type infering:
internal static class ValueOnError
{
public static ValueOnError<TValue> FromValue<TValue>(TValue value)
=> ValueOnError<TValue>.FromValue(value);
}
Then you could just write
var y = ValueOnError.FromValue(Enumerable.Empty<int>());
Upvotes: 1