Это довольно старый вопрос, но недавно у меня возникла такая же проблема. И я не видел ответа, который работает для меня, поэтому я поделюсь найденным решением.
- Почему массив int не может или не может быть приведен или упакован в объект[] или строку[]?
Почему он не упакован, я не знаю. Но его можно явно упаковать, см. решение ниже.
- Почему компилятор этого не улавливает?
Потому что компилятор неправильно интерпретирует ситуацию: тип не совсем массив объектов, поэтому он не знает, что с ним делать, и решает для выполнения .ToString()
над массивом int, который возвращает один единственный параметр, содержащий имя типа, а не сам список параметров. Он не делает этого со строковым массивом, потому что целевой тип уже является строкой, но с любым другим типом массива возникает та же проблема (например, bool[]
).
Рассмотрите var arr1 = new int[]{1,2};
с string.Format("{0}", arr1)
: Пока у вас есть только {0}
в строке формата, вы возвращаете только имя типа "System.Int32[]"
(и никаких исключений не возникает).
Если у вас больше заполнителей, например. string.Format("{0}{1}", arr1)
, то возникает исключение, потому что arr1
неправильно интерпретируется как один параметр, а для компилятора второйй один отсутствует.
Но то, что я считаю концептуальной ошибкой, заключается в том, что вы не можете преобразовать arr1
, т. е. если вы попытаетесь сделать (object[])arr1
-, вы получите: #P2#
Решение:
Заполнение каждого элемента массива int не является решением, которое работает для меня, потому что в моем проекте я динамически создаю строку шаблона формата во время выполнения, содержащую {0}...{n}
, поэтому мне нужно передать массив в String.Format
.
Поэтому я нашел следующий обходной путь. Я создал общую вспомогательную функцию (которая, конечно, может быть и методом расширения, если вы предпочитаете):
// converts any array to object[] and avoids FormatException
object[] Convert<T>(T[] arr)
{
var obj = new List<object>();
foreach (var item in arr)
{
obj.Add((object)item);
}
return obj.ToArray();
}
Теперь, если вы попробуете это в приведенном ниже примере, который показывает FormatException:
// FormatException: Index (zero based) must be greater than or equal to zero
// and less than the size of the argument list
var arr1 = (new int[] { 1, 2 });
string.Format("{0}{1}{0}{1}", arr1).Dump();
Исправлено: используйте Convert(arr1)
в качестве 2nd параметра для string.Format(...)
, как показано ниже:
// Workaround: This shows 1212, as expected
var arr1 = (new int[] { 1, 2 });
string.Format("{0}{1}{0}{1}", Convert(arr1)).Dump();
Попробуйте пример как DotNetFiddle
Вывод: кажется, что среда выполнения .NET действительно неправильно интерпретирует параметр, применяя к нему .ToString()
, если он еще не имеет тип object[]
. Метод Convert
не дает среде выполнения другого выбора, кроме как сделать это правильно, потому что он возвращает ожидаемый тип. Я обнаружил, что явное преобразование типов не работает, поэтому понадобилась вспомогательная функция.
Примечание. Если вы вызываете метод много раз в цикле и вас беспокоит скорость, вы также можете преобразовать все в массив строк, что, вероятно, наиболее эффективно:
// converts any array to string[] and avoids FormatException
string[] ConvertStr<T>(T[] arr)
{
var strArr = new string[arr.Length];
for (int i = 0; i < arr.Length; i++)
{
strArr[i]=arr[i].ToString();
}
return strArr;
}
Это тоже работает. Чтобы преобразовать из другого типа данных, например из словаря, вы можете просто использовать
string[] Convert<K,V>(Dictionary<K,V> coll)
{
return ConvertStr<V>(coll.Values.ToArray());
}
Обновление: с интерполяцией строк есть еще один короткий способ решить эту проблему:
var baz = string.Format("{0} and {1}", myInts.Select(s => $"{s}").ToArray());
person
Matt
schedule
08.05.2018