我正在尝试编写一个
Dbg
调试函数,它将打印出有关给定参数的一些调试信息,然后返回它。我希望将数组打印为元素列表,并使用 .ToString()
打印标量。到目前为止我已经:
public static class Utils
{
/// <summary>
/// Log the given expression to the console iff a debugger is attached,
/// returning that same value transparently. Useful for debugging values
/// without rewriting all your code. Also logs the caller and line
/// number via compiler trickery.
/// </summary>
public static T Dbg<T>(
T thingToLog,
// Ask the compiler to insert the current file, line number, and caller
[CallerFilePathAttribute] string filepath = null,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null
)
{
if (System.Diagnostics.Debugger.IsAttached)
{
string filename = filepath.Split('\\').Last();
// FIXME This doesn't actually print the array, just "System.Byte[]" or similar
string stringToLog = typeof(T).IsArray ? "[ " + String.Join(", ", thingToLog) + " ]" : thingToLog.ToString();
Console.WriteLine($"[{filename}:{lineNumber} {caller}()] {stringToLog}");
}
return thingToLog;
}
}
问题出在这一行:
string stringToLog = typeof(T).IsArray ? "[ " + String.Join(", ", thingToLog) + " ]" : thingToLog.ToString();
它只输出
thingToLog
的类型,就像System.Byte[]
一样,但我希望它输出字节数组中的元素。在调试器中,尝试访问 thingToLog
的元素会导致 thingToLog[0] error CS0021: Cannot apply indexing with [] to an expression of type 'T'
,这很公平。但是如果我尝试转换为 object[]
,那么我会得到 ((object[])thingToLog)[0] error CS0030: Cannot convert type 'T' to 'object[]'. And if I try first cast to an
objectand then to an
object[], I get
'((object[])((object)thingToLog))[0]' 抛出异常输入“System.InvalidCastException”`
是否可以检测
T
是否可枚举,如果是,则枚举要打印的元素?
为了解决这个问题,可以使用反射来处理不同类型的集合和数组。我提供了“Dbg”函数的更新版本,它可以正确处理数组和其他可枚举类型。
using System;
using System.Collections;
using System.Linq;
using System.Runtime.CompilerServices;
public static class Utils
{
public static T Dbg<T>(
T thingToLog,
[CallerFilePath] string filepath = null,
[CallerLineNumber] int lineNumber = 0,
[CallerMemberName] string caller = null
)
{
if (System.Diagnostics.Debugger.IsAttached)
{
string filename = filepath.Split('\\').Last();
string stringToLog;
if (thingToLog is IEnumerable enumerable && !(thingToLog is string))
{
var elements = enumerable.Cast<object>().Select(e => e?.ToString() ?? "null");
stringToLog = "[ " + string.Join(", ", elements) + " ]";
}
else
{
stringToLog = thingToLog?.ToString() ?? "null";
}
Console.WriteLine($"[{filename}:{lineNumber} {caller}()] {stringToLog}");
}
return thingToLog;
}
}
希望这会有所帮助