Объединение 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"}" );