Ответ 1
Прежде всего, я бы поставил под сомнение необходимость в свободном интерфейсе в этом случае, кажется, вы можете легко обойтись с гораздо более простым интерфейсом:
Logger.Debug.Message("Test");
или даже просто:
Logger.Debug("Test");
Однако, если вам действительно нужен/нужен свободный интерфейс, другой способ сделать это - сделать свободный интерфейс работой с параметром метода вместо значения возврата.
Итак, вместо этого:
Method1().Method2().Method3();
а затем забыв окончательный вызов:
Method1().Method2().Method3().Execute();
вместо этого вы могли бы организовать код, возможно, вот так:
Method1(o => o.Method2().Method3());
Чтобы сделать это, вы должны определить объект, по которому вы будете называть все быстрые методы:
public class LoggerOptions
{
public LoggerOptions Debug() { LoggerType = LoggerType.Debug; return this; }
public LoggerOptions Error() { LoggerType = LoggerType.Error; return this; }
public LoggerOptions Message(string message) { ...; return this; }
public LoggerType Type { get; set; }
...
}
Каждый вызов метода здесь изменит объект LoggerOptions, а затем вернет тот же экземпляр назад, чтобы продолжить свободный интерфейс.
а затем:
public static class Logger
{
public static void Log(Func<LoggerOptions, LoggerOptions> options)
{
LoggerOptions opts = options(new LoggerOptions());
// do the logging, using properties/values from opts to guide you
}
}
Затем вы вызываете это следующим образом:
Logger.Log(opts => opts.Debug().Message("Debug message"));
Если у вас есть какие-то терминальные методы, вам абсолютно необходимо позвонить до завершения настройки объекта options, вы можете создавать разные объекты:
public class LoggerOptions
{
public LoggerOptions Debug() { LoggerType = LoggerType.Debug; return this; }
public LoggerOptions Error() { LoggerType = LoggerType.Error; return this; }
public LoggerOptions Message(string message) { ...; return this; }
public LoggerType Type { get; set; }
...
public LoggerFinalOptions ToEventLog() { ...; return new LoggerFinalOptions(this); }
public LoggerFinalOptions ToFile(string fileName) { ...; return new LoggerFinalOptions(this); }
}
а затем:
public static class Logger
{
public static void Log(Func<LoggerOptions, LoggerFinalOptions> options)
{
LoggerFinalOptions opts = options(new LoggerOptions());
// do the logging, using properties/values from opts to guide you
}
}
Тогда это гарантировало бы, что вы не сможете скомпилировать код, не заканчивая цепочку методов вызовом того, что возвращает явный окончательный объект options:
// will not compile
Logger.Log(opts => opts.Debug().Message("Test"));
// will compile
Logger.Log(opts => opts.Debug().Message("Test").ToFile("log.log"));