Сообщество программистов Autodesk в СНГ

ADN Club => Inventor API => Тема начата: R.I.Chernov от 23-03-2016, 15:49:14

Название: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: R.I.Chernov от 23-03-2016, 15:49:14
Доброго времени суток, уважаемые форумчане. Как и упомянуто в теме, прошу вашей помощи в преобразовании кода VBA в C#. Прошу прощения, что это немного оффтопик и не касается Inventor-а, очень надеюсь на ваше понимание. Исходный код в VBA:

Код - Visual Basic [Выбрать]
  1. Dim row_num As Integer
  2. Dim rng As Variant
  3.  
  4. For Each rng In xlsheet.range("A1:A90")
  5. If rng .Value = 75 Then
  6.     If xlsheet.range("B" & rng .Row).Value = 5 Then
  7.     row_num = rng .Row
  8.     End If
  9. End If
  10. Next

И вроде бы код должен быть простым и полностью аналогичным. но не получается записать условия If:
Код - C# [Выбрать]
  1. If (rng .Value == 75)
  2. ....
  3. If ( xlsheet.range("B" + rng .Row).Value == 5)

При запуске программа ругается в обоих местах :  Не удается применить оператор "==" к операндам типа "string" и "int".
Буду благодарен за любой совет!
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: Александр Ривилис от 23-03-2016, 16:50:21
В C# оператор сравнения не = , а ==
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: R.I.Chernov от 23-03-2016, 17:05:31
C# оператор сравнения не = , а ==
Спасибо, Александр, как раз зашел это исправить. Классика жанра: "Учи мат часть!" :)
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: mikazakov от 23-03-2016, 20:03:29
Не удается применить оператор "==" к операндам типа "string" и "int".
Батенька, вы же юзаете C#, главная особенность C# это строгая типизация, т.е. никакого разврата с автоматическим приведением типов. Это позволяет избежать некоторых ошибок и повысить скорость работы программы.
На том клочке кода который вы приводите:
Код - C# [Выбрать]
  1. If (rng .Value == 75)

Я подразумеваю, что переменная rng объявлена как Object (т.к. Variant в C# не существует). И потом вы пытаетесь выдавить с ней свойства Value . А на основании чего компилятор должен понять, что в типе Object такое свойство есть? Он и не понимает этого, то что VBA отскладывает процесс проверки свойств на этап выполнения, не значит что C# так будет делать. Поэтому самое рациональное это приведение типов, например:
Код - C# [Выбрать]
  1. If ((int)rng .Value == 75)
После этого компилятор C# должен "проглотить" эту строку, т.к. ответственность за значение лежит теперь на вас.

Есть еще один подход в C# для случаев взаимодействиями объектными моделями на базе IDispatch (VBA), это объявить переменную с ключевым словом dynamic вместо Object:
Код - C# [Выбрать]
  1. dynamic rng;
тогда компилятор будет молчать и проверять тип переменной во время выполнения программы, но это нужно юзать как крайний случай, потому как это дорожка скользкая.

P.S. так как причесанного примера тут не было, поэтому все здесь на уровне теории, но думаю что вы додумаете как атм у вас правильно, что и где приводить.
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: R.I.Chernov от 24-03-2016, 22:41:55
Спасибо, Михаил. Я еще не до конца разобрался в тех мыслях, которые вы пытались до меня донести в своем сообщении, так что докучаю вас вопросами "по-порядку возникновения" ;)
Я подразумеваю, что переменная rng объявлена как Object (т.к. Variant в C# не существует). И потом вы пытаетесь выдавить с ней свойства Value .
Дело в том, что я использую тип Excel.Range, оболочка процедуры выглядит так:
Код - C# [Выбрать]
  1. foreach (Excel.Range cellNum in xlWorksheet.Range["A1:A90"])
  2. {
  3. }
где xlWorksheet ссылка на лист Excel.
Я покопался на форумах где обсуждается эксель API и, как я  понял, для такого перебора нужен именно тип range. В объектном браузере excel у "Range" указано два свойства Value и Value2. Полагаю что объектная модель неизменна при использовании C# и Excel API?  Вот с помощью них и пытаюсь получить значение ячеек для сравнения. Пока тщетно. Максимум, чего я пока добился, могу вывести номер строк с помощью Debug.WriteLine(cellNum.Row), что уже хорошо, ибо перебор работает в принципе. Причем если использовать Debug.Print(cellNum.Row.ToString), то привести к типу string не выходит, программа говорит что это группа методов и не преобразуется в string формат... В общем сижу и пытаюсь во всех направлениях расширять свои знания C#, например понять, почему  Debug.WriteLine работает, мне казалось что ее от личие от Debug.Print лишь в том, что к формату стринг она приводит "за тебя"?
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: mikazakov от 25-03-2016, 07:54:43
В объектном браузере excel у "Range" указано два свойства Value и Value2.
Если конкретизировать, то здесь похоже, что свойство Value является типом Variant, аналога которого в C# нет. Variant он похож на Object, и тоже позволяет создавать переменные "произвольного" типа. Как я писал выше что Variant в C# упаковывается в Object. И компилятор не может понять какой там тип упакован внутри. Поэтому нужно делать приведение типа у Range.Value . например к int.
Видимо Debug.WriteLine имеет алгоритм который пытается сам анализировать и если это успешно то выводит строку. Бейсик часто так делает.
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: R.I.Chernov от 25-03-2016, 12:14:14
Поэтому нужно делать приведение типа у Range.Value . например к int.
Спасибо, Михаил, я этим как раз и занимаюсь. Хотя в многочисленных примерах с форумов excel как правило встречается value2, так что изучаю оба эти свойства.
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: mikazakov от 25-03-2016, 12:43:25
Хотя в многочисленных примерах с форумов excel как правило встречается value2
MSDN:

Свойство Value2, который можно использовать для объекта Range, практически идентичен свойство Value, за исключением того, что свойство Value2 не использует типы данных даты и валюты.

Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: R.I.Chernov от 25-03-2016, 12:58:55
Да, спасибо, я читал справку. Быть может его предпочитают из за отсутствия аргумента. Я нашёл сейчас одну хорошую статью, в которой описывается, чем отличается программирование в C# в Excel от VBA. Надеюсь найду там все необходимое.
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: mikazakov от 25-03-2016, 13:04:47
Быть может его предпочитают из за отсутствия аргумента.
Думаю, что дело в том, что старый валютный тип упразднен, вместо него сейчас Decimal, но конвертировать старый тип в новый немного заморочено. Видимо с датой тоже самое.
Но в вашем случае, батенька, нужно просто приводить к строковому типу или числовому.
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: R.I.Chernov от 25-03-2016, 16:19:17
Как говорится: "ларчик просто открывался!". Итоговый код (вдруг кому пригодится) получился таким :
Код - C# [Выбрать]
  1. foreach (Excel.Range cellNum in xlWorksheet.Range["A2:A90"])
  2. {
  3.     if (cellNum.Value ==  75)
  4.     {
  5.         if (xlWorksheet.Range["B" + cellNum.Row].Value2 == 3)
  6.         {
  7.         }
  8.     }            
  9. }
где xlWorksheet - ссылка на лист (стоит заметить, что работает и Value и Value2)

Ошибка была в том, что диапазон значений для перебора, помимо числовых значений содержал одно строковое (шапка столбца, название переменной). И, как бы я не пытался привести к какому либо из типов, для сравнения в условии "If", всегда была ошибка (причина, полагаю, понятна). Все спасибо большое за помощь.
П.С. изучая теорию касательно работы с экслеь, я обнаружил, что во многих источниках вместо свойства Workseet.Range, используют метод Workseet.get_Range(). Причем get_Range не выпадает в "подсказке" C# и его можно набить только руками. А в статье для работы с Excel 2003 написано, что для C# необходимо использовать именно get_Range. Вобщем у меня путаница в голове, был бы признателен, если кто-нибудь смог бы мне разъяснить разницу, и есть ли она. Складывается впесатление. что get_Range - пережиток прошлых версий.
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: Александр Ривилис от 25-03-2016, 16:28:42
Как раз рекомендуют использовать свойство Range, а не метод get_Range() : https://msdn.microsoft.com/en-us/library/microsoft.office.tools.excel.worksheet.get_range
Цитировать
Gets a Microsoft.Office.Interop.Excel.Range object that represents a cell or a range of cells. Use the Range property instead of this method.
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: R.I.Chernov от 25-03-2016, 16:34:17
Спасибо, Александр!
Use the Range property instead of this method.
Это справка, я собственно ею и руководствовался, решив не использовать get_Range.
Но я говорил про примеры из форумов:
- просто присутствие get_Range в коде, как здесь: http://www.cyberforum.ru/csharp-beginners/thread644870.html
- так и прямые словесные рекомендации по его использованию как, например, вот в этой статье (правда она очень старая): http://www.ishodniki.ru/art/artshow.php?id=474

У меня пытливый ум. :) Мне не нравится, когда я чего-то не понимаю. Задача решена, а душевного покоя нет! :)
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: mikazakov от 25-03-2016, 17:57:35
Мне не нравится, когда я чего-то не понимаю.
get_Range и set_Range это тоже самое, что и Range[индекс]. Просто раньше индексаторы в C# не поддерживались, их ввели позже для удобства использования коллекций из COM-объектов.

Ну а по поводу разных типов в одном столбце... в перспективе это может быть очень гадко, потому как поставил незаметный пробел рядом с числом в ячейке и там уже не int, а string и все и приехали... поэтому лучше дополнительную проверку делать:

Код - C# [Выбрать]
  1.   object obj = "34";
  2. if (obj is string) Console.WriteLine("String");
  3. if (obj is int) Console.WriteLine("int");
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: R.I.Chernov от 25-03-2016, 18:49:29
поэтому лучше дополнительную проверку делать
Спасибо!
У меня появилась еще одна проблема с поим перебором. Повторно укажу код, чтобы удобнее было читать:
Код - C# [Выбрать]
  1.     foreach (Excel.Range cellNum in xlWorksheet.Range["A2:A90"])
  2.     {
  3.         if (cellNum.Value ==  75)
  4.         {
  5.             if (xlWorksheet.Range["B" + cellNum.Row].Value2 == 5)
  6.             {
  7.              cellNum_main = cellNum;
  8.              abc = (int) cellNum.Row;
  9.             }
  10.         }        
  11.     }
 
Цель перебора - найти нужную строку по двум изменяемым параметрам (лишь для простоты они записаны как 75 и 5). Lальше считать значения переменных из этой строки. Проблема моя в том, что значение cellNum.Row существует лишь внутри процедуры foreach. Я пытался создать переменные типа range и int и приравнять их  к cellNum и (int) cellNum.Row соответственно. Но когда я дальше (за пределами foreach) пытаюсь использовать эти переменный, программа пишет, что им не присвоено значение. :( Причем пишет еще до запуска отладки. Если знаете, посоветуйте пожалуйста, как это решить.
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: mikazakov от 25-03-2016, 19:13:53
Причем пишет еще до запуска отладки. Если знаете, посоветуйте пожалуйста, как это решить.
присвойте при объявлении им null и компилятор успокоится
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: R.I.Chernov от 28-03-2016, 15:59:14
присвойте при объявлении им null и компилятор успокоится
Спасибо, помогло!
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: mikazakov от 28-03-2016, 18:08:06
Спасибо, помогло!
Если любопытно, то можно еще кстати через #pragma warning
https://msdn.microsoft.com/ru-ru/library/441722ys(v=vs.100).aspx
но это обычно муторней и больше кода.
Название: Re: Перебор ячеек Excel. Помогите преобразовать код VBA в C#.
Отправлено: R.I.Chernov от 28-03-2016, 22:31:00
Да не, спасибо за информацию, но с моим уровнем знаний не стоит думаю в такие дебри лезть. Предыдущий ваш способ мне полностью подходит.