Home > other >  How do I do pattern matching against generic type when type parameter is unknown, but effectively no
How do I do pattern matching against generic type when type parameter is unknown, but effectively no

Time:10-22

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
}
  • Related