I have a hierarchy of classes to simulate discriminated union. One such class is a record:
private sealed record ErrorStrWithEnum<TEnum>(string Error, TEnum Enum) : Error
where TEnum : struct, Enum
then I have an object of type Error
and I want to extract the message:
error switch
{
ErrorStrWithEnum<_>(var message, _) => message
}
This obviously does not work. Even if classes supported covariance, I could not match against ErrorStrWithEnum<object>(var message, _)
because cov-/contravariance is not supported for value types.
The alternative is to introduce intermediary type ErrorStrWithEnum(string Error, object Enum)
but it will cause boxing.
Is there any more elegant alternative?
CodePudding user response:
You need introduce either a non-generic record with string for message or interface and match against that:
private record ErrorWithStr(string Error) : Error;
private sealed record ErrorStrWithEnum<TEnum>(string Error, TEnum Enum) : ErrorWithStr(Error)
where TEnum : struct, Enum;
error switch
{
ErrorWithStr(var message) => message
}
or
private interface IHaveError {
string Error { get; }
}
private sealed record ErrorStrWithEnum<TEnum>(string Error, TEnum Enum) : Error, IHaveError
where TEnum : struct, Enum
x switch
{
IHaveError err=> err.Error
}
CodePudding user response:
Records can implement interfaces, so you can expose that string as a interface property:
private interface IHasMessage {
string Message { get; }
}
private sealed record ErrorStrWithEnum<TEnum>(string Message, TEnum Enum)
: Error, IHasMessage
where TEnum : struct, Enum
{
...
}
Then you can match IHasMessage
:
error switch
{
IHasMessage { Message: var message } => message
}