ItemArray в строку с недопустимым форматом

У меня есть DataTable с несколькими DataRow, которые я хочу отформатировать в новом DataTable, но я обнаружил проблему, когда пытаюсь отформатировать некоторые строки:

DataTable ret = functionThatGetsaDataTableUsingSQL(); //Original DataTable
DataTable dt = new DataTable(); //Final DataTable
foreach (DataRow dr in ret.Rows)
{
    DataRow row = dt.Rows.Add();
    for (int j = 0; j < dr.ItemArray.Length; j++)
    {
        if (j == 14) row[j] = dr.ItemArray[j].ToString("C2");
        else row[j] = dr.ItemArray[j];
    }
}

row[j] = dr.ItemArray[j].ToString("C2"); не работает, говоря No overload for method 'ToString' takes 1 arguments

Я попытался максимально упростить код, чтобы сосредоточиться только на части форматирования.

Как я могу отформатировать это значение? Я знаю, что могу разыграть Convert.ToDecimal() перед использованием ToString("C2"), но это ЕДИНСТВЕННЫЙ способ сделать это?


person Miquel Coll    schedule 26.02.2016    source источник
comment
Возможный дубликат без перегрузки для метода ToString принимает 1 аргумент   -  person Alex    schedule 26.02.2016


Ответы (3)


ItemArray это object[]. Object.ToString не имеет параметра. Я предполагаю, что это на самом деле стоимость валюты. Затем используйте метод расширения DataRow.Field, чтобы привести его:

foreach (DataRow dr in ret.Rows)
{
    DataRow row = dt.Rows.Add();
    for (int j = 0; j < dr.ItemArray.Length; j++)
    {
        if (j == 14) 
            row[j] = dr.Field<decimal>(j).ToString("C2"); // use the correct type
        else 
            row[j] = dr.ItemArray[j];
    }
}

Вот оптимизированная версия, ItemArray-property имеет дополнительные накладные расходы, поскольку геттер всегда создает новый массив (как вы можете видеть здесь):

foreach (DataRow dr in ret.Rows)
{
    DataRow row = dt.Rows.Add();
    foreach(DataColumn col in ret.Columns)
    {
        if (col.Ordinal == 14)
            row.SetField(col.Ordinal, dr.Field<decimal>(col).ToString("C2")); // use the correct type
        else
            row.SetField(col.Ordinal, dr[col]);
    }
}
person Tim Schmelter    schedule 26.02.2016
comment
Поле представляет собой десятичное значение, которое я хочу преобразовать в валюту. В любом случае это решило вопрос, который у меня был. Просто знать: есть ли разница между получением значения с использованием ItemArray[i] и Field<type>(i)? Просто спрашиваю, так как это цикл, который будет повторяться как минимум тысячу итераций. - person Miquel Coll; 26.02.2016
comment
@MiquelColl: я отредактировал свой ответ, чтобы показать подход без ItemArray. Вместо SetField вы также можете использовать row[index]=. Первый лучше, если у вас есть типы, допускающие значение NULL. - person Tim Schmelter; 26.02.2016
comment
У меня есть несколько типов, допускающих значение NULL, поэтому SetField звучит как отличный инструмент. У меня впереди работа по изменению стольких ItemArray... - person Miquel Coll; 26.02.2016

C2 означает, что он конвертирует в валюту до 2 знаков после запятой, но что он будет конвертировать, если вы поместите напрямую строку, скажем, «jkld», поэтому обязательно сообщите компилятору ваш тип исходных данных, и как только он будет уверен, что это тип удвоить, тогда он примет вот так

Правильный путь

double myPrice;
myPrice.ToString("C2");

Это теоретический ответ, но вы должны знать, и в будущем вы не запутаетесь, счастливого кодирования :)

person Vinay Sinha    schedule 26.02.2016
comment
Ну, я на самом деле сказал в своем вопросе, что знаю, что десятичное/двойное число можно будет отформатировать, но я хотел знать, есть ли способ опустить приведение или преобразование. Спасибо в любом случае. - person Miquel Coll; 26.02.2016

Вы можете использовать string.Format для чего угодно.

string.Format("{0:C2}", o);

будет компилироваться для любого типа и значения o. Чтобы воспользоваться этим, ваш код будет изменен следующим образом:

DataTable ret = functionThatGetsaDataTableUsingSQL(); //Original DataTable
DataTable dt = new DataTable(); //Final DataTable
foreach (DataRow dr in ret.Rows)
{
    DataRow row = dt.Rows.Add();
    for (int j = 0; j < dr.ItemArray.Length; j++)
    {
        if (j == 14) row[j] = string.Format("{0:C2}", dr.ItemArray[j]);
        else row[j] = dr.ItemArray[j];
    }
}

РЕДАКТИРОВАТЬ: это не означает, что это лучший способ - ответ, использующий метод Field, вероятно, лучше, потому что он и быстрее, и более явный.

Мой метод был бы более подходящим, если бы вы собирались применить этот формат к различным типам с плавающей запятой (или даже целым числам), и вы не знали, какие это будут типы на момент написания кода.

person Richard Irons    schedule 26.02.2016