There's no need for greater accessibility because the delegate infrastructure can connect the delegates
namespace Logger
{
class Program
{
//We need to write the single implementation for the method that writes messages to the console:
public static void LogToConsole(string msg)
{
Console.Error.WriteLine(msg);
}
static void Main(string[] args)
{
var fileOutput = new FileLogger(@"log.txt");
// Logger.WriteMessages += LogToConsole;
string file=null;
Logger.LogMessages(Severity.Warning, file, "T");
}
}
public enum Severity
{
Verbose,
Trace,
Information,
Warning,
Error,
Critical
}
public static class Logger
{
public static Action<string> WriteMessages; //
public static Severity LogLevel { get; set; } = Severity.Warning;
public static void LogMessages(Severity s, string component,string msg)
{
if (s < LogLevel) //如果小于警告级别直接返回
return;
var outputMsg = $"{DateTime.Now}\t{s}\t{component}\t{msg}";
//You may prefer a design that silently continues when no methods have been attached
WriteMessages?.Invoke(outputMsg);
}
}
}
namespace Logger
{
public class FileLogger //
{
public readonly string logPath;
public FileLogger(string path)
{
logPath = path;
Logger.WriteMessages += LogMessage;
}
public void DetachLog() => Logger.WriteMessages -= LogMessage; // cancel relate
private void LogMessage(string msg)
{
try
{
using(var log = File.AppendText(logPath))
{
log.WriteLine(msg);
log.Flush();
}
}
catch
{
//Logging is failing....
}
}
}
}
You won't find the Invoke() method listed in the documentation for System.Delegate or System.MulticastDelegate.
The compiler generates a type safe Invoke method for any delegate type declared.
In this example, that means Invoke takes a single string argument, and has a void return type.