Я пытаюсь написать функцию отладки 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;
}
}
Надеюсь, это поможет
В конце вы спросили: «Можно ли определить, является ли T перечислимым», а это совершенно другая проблема, чем определение того, является ли
T
массивом? Для этого вы можете просто проверитьis IEnumerable
. Если вы действительно хотите проверить массивы, хотите ли вы также проверить двумерные (или более) массивы? В этом случае вы не можете использовать в качестве индекса только одно целое число.