Warning "Message template is not a compile time constant"

Viewed 1240

Within a class I have to following code which occurs several times:

var message = $"My Message with Value1='{value1}' and Value2='{value2}'.";
Log.Error(exception, message);
throw new CustomException(message);

message is always different, but the approach of logging the error and throwing an exception is always the same.

Now both Rider and ReSharper within Visual Studio give the following warning: Message template is not a compile time constant.

I can refactor it into this and the warning goes away:

const string messagePattern = "My Message with Value1='{0}' and Value2='{1}'.";
var messageParameters = new object[] { value1, value2 };
Log.Error(exception, messagePattern, messageParameters);
throw new CustomException(string.Format(messagePattern, messageParameters));

But how can I make this code reusable to avoid that I have to repeat the logging and throwing? This is what I'd like to do:

const string messagePattern = "My Message with Value1='{0}' and Value2='{1}'.";
var messageParameters = new object[] { value1, value2 };
LogAndThrow(exception, messagePattern, messageParameters);

void LogAndThrow(Exception exception, string messagePattern, string messageParameters)
{
    Log.Error(exception, messagePattern, messageParameters);
    throw new CustomException(string.Format(messagePattern, messageParameters));
}

But this gives the same error because messagePattern is not a const anymore and declaring it as in string messagePattern doesn't help.

Is there any way to make this code reusable except disabling the warning?

2 Answers

Currently, your code will throw an exception if the value of value1 is (for example) "{0}". Basically your first piece of code is is not considering what it passes in to be a format string with placeholders, but an already formatted string. You shouldn't call string.Format with that.

I would suggest you provide overloads for LogAndThrow and CustomException that have a single string parameter (for the already-formatted message) and no additional messageParameters parameter (because you don't need it), which does not call string.Format.

To get rid of the warning message should be "My Message with ..." without the $.


Your comments confused me and I came up with the following snippet that contains your desired code. I'm not reviewing your method here, I am addressing the issue of the incorrect use of $.

The result is My Message with Value1='1' and Value2='A'. and not warning (or error if this was .net 5) about message not being a constant.

// BTW. Changed 'string' to 'object[]'
static void LogAndThrow(Exception exception, string messagePattern, object[] messageParameters)
{
    //Log.Error(exception, messagePattern, messageParameters);

    throw new Exception(string.Format(messagePattern, messageParameters));
}

static void Main()
{
    try
    {
        const string messagePattern = "My Message with Value1='{0}' and Value2='{1}'."; // No $
        var messageParameters = new object[] { 1, "A" };
        LogAndThrow(new Exception("X"), messagePattern, messageParameters);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}
Related