Вопросов на e-mail приходит много… довольно большая их часть касается темы программирования. В рамках этого небольшого материала я отвечу на те письма, которые сохранял и складировал в своей папке «Вопросы по C#»… за последние два месяца. Хотя последний ответ в данной подборке я взял из своих старых подборок вопрос-ответов, потому как отвечать много раз на одно и то же не хотелось.
Итак, поехали, читаем первое письмо:
***
С уважением, Андрей»
Вы немного запутались, что, в принципе, среди open source продуктов сделать довольно просто:). Mono (на который вы дали ссылку), является развитым кроссплатформенным проектом на базе бесплатного ПО, заменяющим программную платформу .NET Framework. То есть, это компиляторы, отладчики и так далее. К нему могут привязываться графические библиотеки элементов интерфейса GTK+, wxWidgets (а точнее разновидность wx.NET). То есть, Mono следует рассматривать как бесплатную альтернативу .NET. Mono актуален большей частью для создания кроссплатформенных приложений.
Если же вы хотите непосредственно программировать как в Visual Studio, то вам понадобится среда разработки и проектирования, и первое, что вам предложат — это MonoDevelop ( http://monodevelop.com/). Скорее всего именно с ней вы и спутали проект Mono. Но (!) при этом, например, при установке Windows-варианта этой IDE в качестве базовой основы (компиляторы и т.п.) вам предложат не Mono, а .NET Framework от Microsoft, а также специальную адаптацию GTK+ — GTK # для .NET.
В принципе, этот вариант не намного сильнее предлагаемого Microsoft’ом бесплатного Visual C# Express.
Лично я, если стоит задача создания .NET-приложений с требованиями по использованию бесплатного ПО разработки, использую другую IDE, а именно SharpDevelop или как ее называют часто #develop ( http://www.icsharpcode.net). По функциональности интерфейса она очень близка к Visual C# для Microsoft. Причем стоит отметить, что упомянутая выше MonoDevelop в одно время было простым ответвлением SharpDevelop, а точнее, SharpDevelop на Mono/GTK+. Теперь это различные IDE.
Но, в принципе, если говорить, например, о C и C++, то бесплатные компиляторы и IDE являются вполне конкурентоспособными, а иногда даже и более выигрывающими по сравнению с брендовыми и коммерческими. Про C# так сказать нельзя, потому как язык в значительной мере заточен под технологии Microsoft.
***
Идем дальше. Читаю следующее письмо…:) Ну, вот, кто так на C# пишет код: string stroka1 = TextBox1.Text.ToString()? Как говорится: «аффтар жжот плюсадин». Для тех, кто не понял, разъясню: TextBox1.Text — это уже значение строчного типа string. Хотя, в принципе, это можно списать на так называемое «замыливание» взгляда, поскольку множество компонент требуют приведения типов.
А вопрос касается… замены символов в строке, в которую загружен большой объем текста. Я думаю, что написавший уже и сам нашел ответ пока дожидался моего. В принципе, все просто, — в стандартном варианте это делается с помощью метода Replace класса String, хотя, если речь идет не об очень больших текстах, я обычно использую более быстрый Replace от класса String Builder, у него другая структура работы. Читайте MSDN. Для рабочего примера, давайте реализуем функцию, которая бы правильно расставляла пробелы вокруг двоеточий в любом приходящем тексте:
static string EditFunc(string p) { StringBuilder b = new StringBuilder(p); b.Replace(" :", ":"); b.Replace(":", ": "); b.Replace(" ", " "); return b.ToString(); }
***
Следующее письмо интересно, хотя сам код автора не привожу, поскольку он большой:
Помогите, пожалуйста, я делаю программу, работающую с базой данных. Как обойти DBConcurrencyException — исключение, которое вызывается DataAdapter при операции вставки, обновления или удаления не затронувшей ни одной строки. Посмотрите код, в чем ошибка? Там DataAdapter помещен в lock(), как мне посоветовали, это не помогло, и нужно ли вообще использовать lock()?
М-да, ну, lock() — это, конечно, всегда хорошо. Например, когда я пишу серьезное приложение на C#, то наиболее часто встречаемыми конструкциями в моем коде являются try — catch и lock() (или подобные решения).
Теперь по вашему коду. Во-первых, главная ошибка всех начинающих, работающих с DataGridView и пытающимся изменить содержимое БД программно. Дело в том, что элемент DataGridView только отображает данные таблицы DataTable. Чтобы внести изменения в отображение, вы должны вносить изменения в DataTable. Поэтому программным присваиванием…
dataGridView1.Rows[i].Cells[18].Value = baseId [i];
вы фактически ничего не делаете, точнее, просто меняете внешний вид. На самом деле изменения нужно вносить хотя бы так:
((DataTable)dataGridView1.DataSource).Rows[i][18] = baseId [i];
После делаете Update объекта DataAdapter. Многие путаются в этом вопросе по той причине, что если изменения вносятся вручную пользователем на объекте DataGridView, они вносятся в DataTable и обновления происходят успешно. Но программно ситуацию нужно решать по-другому.
DBConcurrencyException в большинстве случаев возникает из-за нарушения параллелизма, когда изменения вносятся до фактического обновления объекта DataTable.
При этом DataAdapter после генерации исключения останавливает свою работу и появляется соответствующая ошибка. Обойти это можно, задав свойство DataAdapter. ContinueUpdateDnError как true (по умолчанию оно является false). Затем можно просканировать ошибки в DataTable.HasErrors (см. справочную информацию по нему). Переходим к следующему вопросу, и он опять… об ошибке…
***
Кристофер, не могу понять, в чем дело, сканю Excel-базы и связанные с ними Word-файлы, все проходит с треском, но идет, добавляю вызов функции сверки текста, выскакивает «ContextSwitchDeadlock was detected Message: The CLR has been unable to transition from COM context 0x159bc0 to COM context 0x1598e0 for 60 seconds…» У меня вхождения в бесконечный цикл нет, я проверял, таймеры также не использую. Как решить проблему? Жду скорого ответа!
Эту ошибку часто именуют ошибкой длительных процессов. Если говорить простыми словами, в данном случае отладчик предполагает, что у вас есть некий неправильный процесс, опираясь на то, как программа себя ведет. В принципе, в большинстве случаев я встречал этот вариант при работе с Excel-файлами:), хотя варианты бывали различными. В вашем случае я бы рекомендовал «как можно меньше Excel’а», например, загрузив его через OleDb в DataGridView, после чего оперируя только данными из этого визуального представления (а не перелопачивая файл), во-вторых, я бы порекомендовал более грамотно обращаться с потоками, например, содержать как можно меньше вычислений в основном рабочем потоке, это же относится и к визуальным компонентам, которые отображают процессы.
Ну, и если вы во всем уверены, что все работает правильно ContextSwitchDeadlock можно просто отключить в отладчике Debug->Exceptions->Managed Debug Assistants (отключаем птичку напротив ContextSwitchDeadlock).
***
«Тестируем игровое приложение… основной код на C#... иногда появляются просто глюки…».
И так далее. В общем, при переписке выяснилось, что в рамках программы реализовано много потоков, которые обращаются к одному и тому же объекту. Проблема, кстати, довольно часто встречаемая. В таких случаях нужно делать синхронизацию, для чего читайте хорошие книги, например, ту же «библию» Троелсена, а так просто обозначу основные методы для C#...
В самом простом случае синхронизация доступа осуществляется за счет использования оператора lock(а в скобках указывается маркер), т.е. см. документацию по этому поводу. При этом lock является сокращенным вариантом типа класса System.Threading.Monitor, используя который вы получите чуть большую степень управления по сравнению с первым из предложенного, хотя и более громоздкую. Также можно задействовать для синхронизации класс System.Threading.Interlocked, что будет эргономичнее для программирования. Помимо этого есть и еще один вариант, а именно, атрибут [Synchronization] определенный в пространстве имен System.Runtime.Remoting.Contexts. То есть, тут все на ваше усмотрение. Думается, что четырех вариантов хватит, хотя их может быть гораздо больше, важна также и специфика выполняемых в рамках этих потоков задач.
Кристофер Перепечатка материалов или их фрагментов возможна только с согласия автора
|