c# - 在 C# 中是否有更聪明的方法来重载一组具有不同名称和多个签名的方法?
问题描述
我正在构建一个日志记录类,它根据方法名称以不同的方式格式化消息。我希望能够以与 Console.WriteLine() 工作方式类似的方式使用它。重载工作得很好,但我想用一组不同的方法来做到这一点,名称是格式化选项的决定因素。
我正在寻找是否有一种“更智能”的方法来做到这一点,然后一遍又一遍地编写同一方法的每个版本的每个重载方法。感觉就是这样,容易出错。
我想如何使用它的一些例子:
Logger Log = new Logger();
Log.Prod ("Main Log Window");
Log.Warn ("This is a Warning Message");
Log.Error ("This is an Error Message");
Log.Network ("This is a Network Message");
Log.Verbose ("This is for Verbose Message Reporting");
Log.Processing ("Analaysis Related Message");
我的意思是如何使用 Console.WriteLine,我的意思是这样的:
String Name = "Sam";
String Day = "Monday";
int hour = 11;
int minute = 30;
Console.WriteLine ("Hello World");
Console.WriteLine ("Hello {0}", Name);
Console.WriteLine ("{0}, the time is {1}:{2}", Name, hour, minute);
所以,我最终得到的更像是这样的:
Logger Log = new Logger();
Log.Prod ("Staring Application");
Log.Warn ("Data {0} looks Corrupt",data);
Log.Error ("Error: {0}", message);
Log.Network ("User {0} logged in from {1}", user, network);
Log.Verbose ("This is for Verbose Message Reporting");
Log.Processing ("Analaysis Related Message");
现在,我知道我可以为同一例程的每个版本编写每个重载方法(请记住,每个版本的消息格式都会略有不同),并且我可以在其上添加某种“代码”,例如:
Log.Write (Log.Error ,"Error: {0}", message);
...和 Log.Error 是某种枚举或任何东西,但这很讨厌。
我想做的就是将这一切都归结为一个 case 语句,该语句将处理格式,然后将其输入到输出中。我需要编写的大部分代码都是重载中继,99% 重复相同的事情。必须有更聪明的方法。
我已经在其他语言中看到了一些可能会这样做的东西,但如果可能的话,我正在寻找一种 C# (.Net Framework 4.8) 方法来做到这一点。除了全部写出来之外,“最干净”和“更聪明”的做法是什么?
我已经研究过重载、覆盖、模板、接口等。但到目前为止,这一切看起来好像最终会是相同的结果或更糟。
- 编辑
我有一个旧版本,它做了这样的事情:
...
public static void Log (Type LogType, object Msg, object [] args ) {
// Using Type specifier and format options.
String NewMsg = String.Format (Msg.ToString(), args);
Logger.Log ((int) LogType, NewMsg);
}
public static void Log (Type LogType, object Msg, object arg1, object arg2 ) {
// Using Type specifier and format options.
String NewMsg = String.Format (Msg.ToString(), arg1, arg2);
Logger.Log ((int) LogType, NewMsg);
}
public static void Log (Type LogType, object Msg, object arg1, object arg2, object arg3 ) {
// Using Type specifier and format options.
String NewMsg = String.Format (Msg.ToString(), arg1, arg2, arg3);
Logger.Log ((int) LogType, NewMsg);
}
...
我想看看我是否可以摆脱那个“类型”参数并使用函数的名称来转发它。也许那是某种模板或重载。我想我可能已经从 Console.WriteLine 中进行了一些复制/粘贴(已经有一段时间了),或者至少将它用作起点。
我知道很长的路要走,我只是希望有一个“更智能”的版本,但到目前为止,似乎还没有一个。
这可能有错误,只是把它放在一起作为一个漫长的例子......
...
public static void Warn(object Msg, object[] args) {
// Using Type specifier and format options.
String NewMsg = String.Format (Msg.ToString(), args);
Logger.Log(1, NewMsg);
}
public static void Warn(object Msg, object arg1, object arg2) {
// Using Type specifier and format options.
String NewMsg = String.Format (Msg.ToString(), arg1, arg2);
Logger.Log(1, NewMsg);
}
public static void Warn(object Msg, object arg1, object arg2, object arg3) {
// Using Type specifier and format options.
String NewMsg = String.Format (Msg.ToString(), arg1, arg2, arg3);
Logger.Log(1, NewMsg);
}
...
public static void Error(object Msg, object[] args) {
// Using Type specifier and format options.
String NewMsg = String.Format (Msg.ToString(), args);
Logger.Log(2, NewMsg);
}
public static void Error(object Msg, object arg1, object arg2) {
// Using Type specifier and format options.
String NewMsg = String.Format (Msg.ToString(), arg1, arg2);
Logger.Log(2, NewMsg);
}
public static void Error(object Msg, object arg1, object arg2, object arg3) {
// Using Type specifier and format options.
String NewMsg = String.Format (Msg.ToString(), arg1, arg2, arg3);
Logger.Log(2, NewMsg);
}
...
所以,如果我做我想做的事,那可能会很长,我可以,我只是想知道是否有更好的方法。
那是我学习超载的时候,所以,是的。
--- 编辑:工作:
我不得不做一些技巧来让它全部旋转,但是如果有人需要它,这就是我想出的:
工作示例代码片段:
Logger Log = new Logger();
String name = "George";
long records = 200000;
String network = "someplace.com";
int hour = 10;
int minute = 30;
Log.Prod ();
Log.Warn ("Project Starting");
Log.Warn (network);
Log.Prod ("Hello {0}!", name);
Log.Prod ($"Hello {name}!");
Log.Processing("{0} Processed", records);
Log.Processing($"{records} Processed");
Log.Network($"{name} logged in from {network} at {hour}:{minute}");
Log.Network("{0} logged in from {1} at {2}:{3}", name, network, hour, minute);
现在,我还没有我的格式的东西,(不相关,但可以使用该值,它将进入控制台日志窗口,因此它们将被着色并且各种图章将包装它们,但这是简单的部分为以后。)
public class Logger {
public Logger () {
if (LogSubsystem.Init == true) {
return;
} else {
// Do some setup stuff here.
}
}
public void Prod(params object[] args) {
LogMessage(1, args);
}
public void StatusBar(params object[] args) {
LogMessage(2, args);
}
public void TitleBar(params object[] args) {
LogMessage(3, args);
}
public void Verbose(params object[] args) {
LogMessage(4, args);
}
public void Status(params object[] args) {
LogMessage(5, args);
}
public void Network(params object[] args) {
LogMessage(6, args);
}
public void Account(params object[] args) {
LogMessage(7, args);
}
public void Error(params object[] args) {
LogMessage(8, args);
}
public void Warn(params object[] args) {
LogMessage(9, args);
}
public void Processing(params object[] args) {
LogMessage(10, args);
}
public void DebugLow(params object[] args) {
LogMessage(11, args);
}
public void DebugMid(params object[] args) {
LogMessage(12, args);
}
public void DebugHigh(params object[] args) {
LogMessage (13, args);
}
private void LogMessage(int mode, object [] args) {
var property = typeof(ICollection).GetProperty("Count");
int count = (int)property.GetValue(args, null);
... many things missing....
if (count == 0) {
Console.WriteLine ("");
}
if (count == 1) {
Console.WriteLine ("{0}", args[0]);
}
if (count > 1) {
ArraySegment<object> ASargs = new ArraySegment<object>(args, 1, (count-1));
object [] SubArgs = ArraySegmentToArray(ASargs);
Console.WriteLine (args[0].ToString(), SubArgs);
}
}
private object [] ArraySegmentToArray (ArraySegment<object> segment) {
var result = new object[segment.Count];
for (int i = 0; i < segment.Count; i++) {
result[i] = segment.Array[i + segment.Offset];
}
return result;
}
} // Logger class
并且输出有效:
项目启动 某地.com 你好乔治! 你好乔治! 200000 已处理 200000 已处理 George 于 10:30 从 someplace.com 登录 George 于 10:30 从 someplace.com 登录
其中一些最终会设置状态栏、标题栏等,这就是它们存在的原因。(您会在此处尚不存在的东西中设置对这些对象的引用,我的旧对象会这样做,因此,将其移过来)棘手的部分是 ArraySegment Stuff,也许是一种更简单的方法,但它是足够短并且我不在乎的作品。惊讶地发现 ArraySegment 没有 ToArray(),是的,没有看到那个。总之感谢!!!
解决方案
params
应该为您解决问题。您不需要对同一个名称进行多个覆盖。只有一个人会做。
public static void Warn(string msg, params object[] args) {
Logger.Log(1, String.Format(msg, args));
}
public static void Error(string msg, params object[] args) {
Logger.Log(2, String.Format(msg, args));
}
等等。
推荐阅读
- rust - 如何为具有生命周期成员的结构派生 serde::Deserialize
- python - 将过滤后的 json 值写入 csv
- python - 使用 ipAPI 和 Django 获取浏览器的位置
- postgresql - postgres/data/pgdata 不是 Kubernetes 工作负载中的有效数据目录
- android - 在 Logcat 中仅显示带有特定名称项的标记
- java - HashMap到带有嵌套对象的json字符串
- python - 如何使用独立于程序运行开始时间的 apscheduler 每隔一小时执行一次 python 函数
- javascript - 如何在 asp:GridView 中检查另一个时取消选中已检查的 asp:CheckBox
- dns - 同时解析本地 DNS 和 Google Cloud 内部 DNS
- c# - 如何在 Unity android 项目中为 Firebase 分析事件启用调试模式?