Объединение CallerMemberName с параметрами

Прямо сейчас (C# 4.0) наш метод регистрации выглядит

public void Log(string methodName, string messageFormat, params object[] messageParameters)

где регистратор выполняет форматирование строки, так что вызывающая сторона не помещает String.Format для создания хорошего сообщения журнала (и позволяет регистратору пропускать форматирование строки, если журнал не подключен).

В C# 5.0 я хотел бы избавиться от параметра methodName с помощью нового атрибута CallerMemberName, но я не вижу, как это можно объединить с ключевым словом 'params'. Есть ли способ сделать это?

3 ответа

Решение

Я считаю, что вы просто не можете объединить params и необязательные параметры, которые требуются для CallerMemberName, Лучшее, что вы можете сделать, это использовать реальный массив вместо params,

Вы могли бы сделать что-то вроде этого:

protected static object[] Args(params object[] args)
{
    return args;
}

protected void Log(string message, object[] args = null, [CallerMemberName] string method = "")
{
    // Log
}

Чтобы использовать журнал, сделайте так:

Log("My formatted message a1 = {0}, a2 = {2}", Args(10, "Nice"));

Чтобы основываться на ответе @guilhermekmelo, я мог бы предложить использовать связанный метод:

Так что держите свой текущий Log(string,string,object[] метод:

      public void Log(string methodName, string messageFormat, params object[] messageParameters)

И добавьте эту новую перегрузку ( Log(string,string)):

      public LogMessageBuilder Log(string messageFormat, [CallerMemberName] string methodName = null)
{
    // Where `this.Log` is 
    return new LogMessageBuilder( format: messageFormat, logAction: this.Log );
}

public struct LogMessageBuilder
{
    private readonly String format;
    private readonly String callerName;
    private readonly Action<String,String,Object[]> logAction;

    public LogMessageBuilder( String format, String callerName, Action<String,String,Object[]> logAction )
    {
        this.format = format;
        this.callerName = callerName;
        this.logAction = logAction;
    }

    public void Values( params Object[] values )
    {
        this.logAction( this.format, this.callerName, values );
    }
}

Используется так:

      this.Log( "My formatted message a1 = {0}, a2 = {2}" ).Values( 10, "Nice" );

Обратите внимание, что LogMessageBuilder это struct, поэтому это тип значения, что означает, что он не вызовет другого выделения сборщика мусора, хотя использование params Object[]вызовет выделение массива на сайте вызова. (Я бы хотел, чтобы C # и .NET поддерживали вариативные параметры на основе стека вместо того, чтобы имитировать их с помощью массива параметров, выделенного кучей).


Другой вариант - использовать, но обратите внимание, что из-за того, что C # компиляторимеет встроенную магию особого случая, вам нужно быть осторожным, чтобы не позволить неявно преобразовать его в String (также отстой, что вы не можете добавить методы расширения в FormattableString прямо, ворчать):

      public void Log(FormattableString fs, [CallerMemberName] string methodName = null)
{
    
    this.Log( messageFormat: fs.Format, methodName: methodName, messageParameters: fs.GetArguments() );
}

Применение:

      this.Log( $"My formatted message a1 = {10}, a2 = {"Nice"}" );
Другие вопросы по тегам