Это не лучший подход для таких изменений с циклом набора записей.
, например
UPDATE tblGuardians
SET FirstName = Trim(StrConv(FirstName, 3))
WHERE StrComp(FirstName, Trim(StrConv(FirstName, 3)), 0) <> 0
, и то же самое для LastName
.
Используется вместо StrComp
вместо простого <>
, потому что последнее нечувствительно к регистру. Третий параметр 0
= vbBinaryCompare
.
Две вещи:
try
{
throw new ArgumentException("some operation that throws an exception");
string s = "blah";
}
catch (e as ArgumentException)
{
Console.Out.WriteLine(s);
}
Это явно проблема - когда вы дойдете до обработчика исключений, s не будет объявлен. Учитывая, что уловы предназначены для обработки исключительных обстоятельств, а finallys должен выполнять , будучи безопасным и объявляет, что проблема во время компиляции намного лучше, чем во время выполнения.
Как вы могли быть уверены, что достигли части объявления в своем блоке catch? Что делать, если экземпляр создает исключение?
Как было указано другими пользователями, фигурные скобки определяют область видимости почти в каждом языке стиля С., о котором я знаю.
Если это простая переменная, то почему вас это волнует, будет в сфере охвата? Это не так уж важно.
в C #, если это сложная переменная, вам нужно реализовать IDisposable. Затем вы можете использовать try / catch / finally и вызвать obj.Dispose () в блоке finally. Или вы можете использовать ключевое слово using, которое автоматически вызовет Dispose в конце раздела кода.
C # 3.0:
string html = new Func<string>(() =>
{
string webpage;
try
{
using(WebClient downloader = new WebClient())
{
webpage = downloader.DownloadString(url);
}
}
catch(WebException)
{
Console.WriteLine("Download failed.");
}
return webpage;
})();
Как указано ravenspoint, все ожидают, что переменные будут локальными для блока, в котором они определены. try
вводит блок, а также catch
.
Если вы хотите, чтобы переменные были локальными для обоих try
и catch
, попробуйте включить оба блока:
// here is some code
{
string s;
try
{
throw new Exception(":(")
}
catch (Exception e)
{
Debug.WriteLine(s);
}
}
Простой ответ: C и большинство языков, унаследовавших его синтаксис, являются блочными. Это означает, что если переменная определена в одном блоке, т. Е. Внутри {}, то есть в ее области.
Исключением, кстати, является JavaScript, который имеет похожий синтаксис, но является областью действия функции , В JavaScript переменная, объявленная в блоке try, находится в области видимости в блоке catch и везде в ее содержащей функции.
Вы решили именно то, что вам следует делать. Вы не можете быть уверены, что ваше объявление было даже достигнуто в блоке try, что приведет к другому исключению в блоке catch.
Он просто должен работать как отдельные области.
try
dim i as integer = 10 / 0 ''// Throw an exception
dim s as string = "hi"
catch (e)
console.writeln(s) ''// Would throw another exception, if this was allowed to compile
end try
Традиционно, на языках C-стиля, то, что происходит внутри фигурных фигурных скобок, остается внутри фигурных скобок. Я думаю, что наличие времени переменного растяжения в таких областях было бы неинтуитивным для большинства программистов. Вы можете добиться того, чего хотите, включив блоки try / catch / finally внутри другого уровня фигурных скобок. например,
... code ...
{
string s = "test";
try
{
// more code
}
catch(...)
{
Console.Out.WriteLine(s);
}
}
EDIT: Я думаю, что каждое правило имеет исключение. Допустим, что C ++:
int f() { return 0; }
void main()
{
int y = 0;
if (int x = f())
{
cout << x;
}
else
{
cout << x;
}
}
Область действия x является условным, предложением then и предложением else.
Поскольку блок try и блок catch являются 2 разными блоками.
В следующем коде вы ожидали бы, что s, определенный в блоке A, будет видимым в блоке B?
{ // block A
string s = "dude";
}
{ // block B
Console.Out.WriteLine(s); // or printf or whatever
}
Согласно разделу «Как выбрасывать и выхватывать исключения» в уроке 2 учебного комплекта для самостоятельного обучения MCTS (экзамен 70-536): Microsoft® .NET Framework 2.0-Application Development Foundation, причина в том, что исключение возможно, произошли до объявления переменных в блоке try (как уже отмечали другие).
Цитата со страницы 25:
"Обратите внимание, что объявление StreamReader было перемещено за пределы блока Try в предыдущем примере это необходимо, потому что блок finally не может получить доступ к переменным, объявленным в блоке Try. Это имеет смысл, поскольку в зависимости от того, где произошло исключение, объявления переменных в блоке Try могут еще не выполняться ".
Когда у вас есть попытка поймать, вы должны в большинстве своем знать, что ошибки, которые он может бросить. Эти классы Exception normaly рассказывают все, что вам нужно об исключении. Если нет, вы должны сделать свои собственные классы исключений и передать эту информацию. Таким образом, вам не нужно будет получать переменные из блока try, потому что Exception является самообучающим. Поэтому, если вам нужно сделать это много, подумайте о своем дизайне и попытайтесь подумать, есть ли какой-то другой способ, вы можете либо предсказать исключения, либо использовать информацию, исходящую из исключений, а затем, возможно, изменить ваши собственные исключение с дополнительной информацией.
Все остальные подняли основы - что происходит в блоке, остается в блоке. Но в случае .NET может оказаться полезным изучить, что думает компилятор. Возьмем, к примеру, следующий код try / catch (обратите внимание, что StreamReader объявлен правильно за пределами блоков):
static void TryCatchFinally()
{
StreamReader sr = null;
try
{
sr = new StreamReader(path);
Console.WriteLine(sr.ReadToEnd());
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
if (sr != null)
{
sr.Close();
}
}
}
В MSIL будет скомпилировано что-то похожее на следующее:
.method private hidebysig static void TryCatchFinallyDispose() cil managed
{
// Code size 53 (0x35)
.maxstack 2
.locals init ([0] class [mscorlib]System.IO.StreamReader sr,
[1] class [mscorlib]System.Exception ex)
IL_0000: ldnull
IL_0001: stloc.0
.try
{
.try
{
IL_0002: ldsfld string UsingTest.Class1::path
IL_0007: newobj instance void [mscorlib]System.IO.StreamReader::.ctor(string)
IL_000c: stloc.0
IL_000d: ldloc.0
IL_000e: callvirt instance string [mscorlib]System.IO.TextReader::ReadToEnd()
IL_0013: call void [mscorlib]System.Console::WriteLine(string)
IL_0018: leave.s IL_0028
} // end .try
catch [mscorlib]System.Exception
{
IL_001a: stloc.1
IL_001b: ldloc.1
IL_001c: callvirt instance string [mscorlib]System.Exception::ToString()
IL_0021: call void [mscorlib]System.Console::WriteLine(string)
IL_0026: leave.s IL_0028
} // end handler
IL_0028: leave.s IL_0034
} // end .try
finally
{
IL_002a: ldloc.0
IL_002b: brfalse.s IL_0033
IL_002d: ldloc.0
IL_002e: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0033: endfinally
} // end handler
IL_0034: ret
} // end of method Class1::TryCatchFinallyDispose
Что мы видим? MSIL уважает блоки - они являются неотъемлемой частью базового кода, сгенерированного при компиляции вашего C #. Объем не просто установлен в спецификации C #, но и в спецификации CLR и CLS.
Объем защищает вас, но вам иногда приходится обходить его. Со временем вы привыкаете к этому, и он начинает чувствовать себя естественным. Как и все остальные, что происходит в блоке, остается в этом блоке. Вы хотите поделиться чем-то? Вы должны выйти за пределы блоков ...
Я думал, что, поскольку что-то в блоке try вызвало исключение, его содержимое пространства имен не может быть доверено, то есть ссылка на String 's' в блоке catch может вызвать бросок еще одного исключения.
Переменные являются уровнем блока и ограничены этим блоком Try или Catch. Аналогично определению переменной в выражении if. Подумайте об этой ситуации.
try {
fileOpen("no real file Name");
String s = "GO TROJANS";
} catch (Exception) {
print(s);
}
Строка никогда не будет объявлена, поэтому на нее нельзя полагаться.
Хорошо, если он не выдает ошибку компиляции, и вы можете объявить ее для остальной части метода, тогда не будет никакого способа объявить ее только в пределах области проверки. Это заставляет вас быть явным в отношении того, где предполагается, что переменная существует, и не делает предположений.
Хотя в вашем примере странно, что это не сработает, возьмите этот схож:
try
{
//Code 1
String s = "1|2";
//Code 2
}
catch
{
Console.WriteLine(s.Split('|')[1]);
}
Это заставит catch выкидывать исключение нулевой ссылки, если код 1 сломался. Теперь, когда семантика try / catch довольно хорошо понята, это будет раздражающим угловым случаем, так как s определяется с начальным значением, поэтому теоретически оно никогда не должно быть нулевым, но в рамках разделяемой семантики это будет.
Опять это теоретически можно было бы зафиксировать, разрешив только разделенные определения (String s; s = "1|2";
) или какой-либо другой набор условий, но, как правило, проще сказать «нет».
Кроме того, это позволяет определять семантику области видимости в глобальном масштабе без исключения, в частности, местные жители сохраняются до тех пор, пока {}
они определены во всех случаях. Малая точка, но точка.
Наконец, чтобы сделать то, что вы хотите, вы можете добавить набор скобок вокруг try catch. Дает вам объем, который вы хотите, хотя он и стоит за небольшую удобочитаемость, но не слишком много.
{
String s;
try
{
s = "test";
//More code
}
catch
{
Console.WriteLine(s);
}
}
В C ++, во всяком случае, область автоматической переменной ограничена фигурными фигурными скобками, которые ее окружают. Почему кто-то ожидает, что это будет отличаться, перелистывая ключевое слово try за фигурные скобки?
Что делать, если исключение создается в некотором коде, который выше объявления переменной. Это означает, что сама декларация не была в этом случае.
try {
//doSomeWork // Exception is thrown in this line.
String s;
//doRestOfTheWork
} catch (Exception) {
//Use s;//Problem here
} finally {
//Use s;//Problem here
}
Если на какой-то момент мы не будем игнорировать проблему контрольного блока, то в ситуации, которая недостаточно четко определена, сложнее будет работать намного сложнее. Хотя это не невозможно, ошибка определения области охвата также заставляет вас, автора кода, реализовать импликацию кода, который вы пишете (что строка s может быть нулевой в блоке catch). Если ваш код был законным, в случае исключения OutOfMemory s даже не гарантированно выделяется слот памяти:
// won't compile!
try
{
VeryLargeArray v = new VeryLargeArray(TOO_BIG_CONSTANT); // throws OutOfMemoryException
string s = "Help";
}
catch
{
Console.WriteLine(s); // whoops!
}
CLR (и, следовательно, компилятор) также заставляет вас инициализировать переменные прежде чем они будут использованы. В представленном блоке catch он не может этого гарантировать.
Итак, мы получаем компилятор, который должен много работать, что на практике не приносит большой пользы и, вероятно, путает людей и побуждает их спрашивать, почему try / catch работает по-разному.
В дополнение к согласованности, не позволяя ничего фантазии и придерживаясь уже установленной семантики семантики, используемой на всем языке, компилятор и CLR могут обеспечить большую гарантию состояния переменной внутри catch блок. Это означает, что он существует и был инициализирован.
Обратите внимание, что разработчики языка отлично поработали с другими конструкциями, такими как , используя блокировку и , где проблема и область видимости определена, что позволяет писать более четкий код.
например с использованием ключевого слова с объектами IDisposable в:
using(Writer writer = new Writer())
{
writer.Write("Hello");
}
эквивалентно:
Writer writer = new Writer();
try
{
writer.Write("Hello");
}
finally
{
if( writer != null)
{
((IDisposable)writer).Dispose();
}
}
Если ваш try / catch / наконец-то трудно понять, попробуйте рефакторинг или введите другой слой косвенности с промежуточным классом, который инкапсулирует семантику того, что вы пытаетесь выполнить. Не видя реального кода, трудно быть более конкретным.
Если операция присваивания завершилась неудачей, ваш оператор catch будет иметь нулевую ссылку обратно на непризнанную переменную.
В конкретном примере, который вы указали, инициализация s не может генерировать исключение. Таким образом, вы можете подумать, что, возможно, его область действия может быть расширена.
Но в целом выражения инициализации могут генерировать исключения. Это не имело бы смысла для переменной, инициатор которой выбрал исключение (или которое было объявлено после другой переменной, где это произошло), чтобы быть в области catch / finally.
Кроме того, пострадает читаемость кода. Правило в C (и последующие языки, включая C ++, Java и C #) просты: области переменных следуют за блоками.
Если вы хотите, чтобы переменная была в области try / catch / finally, но нигде else, затем заверните все это в другой набор фигурных скобок (пустой блок) и объявите переменную перед попыткой.
Функция C # Spec (15.2) утверждает: «Область локальной переменной или константы, объявленной в блоке, является блоком».
(в первом примере блок try это блок, в котором объявлено «s»)
С уважением, tamberg
@burkhard имеет вопрос, почему правильно ответил, но в качестве примечания я хотел добавить, в то время как ваш рекомендуемый пример решения хорош 99.9999 +% времени, это не очень хорошая практика, гораздо безопаснее либо проверить null, прежде чем использовать что-либо, созданное в блоке try, или инициализировать переменную чем-то вместо того, чтобы просто объявлять ее перед блоком try. Например:
string s = String.Empty;
try
{
//do work
}
catch
{
//safely access s
Console.WriteLine(s);
}
Или:
string s;
try
{
//do work
}
catch
{
if (!String.IsNullOrEmpty(s))
{
//safely access s
Console.WriteLine(s);
}
}
Это должно обеспечить масштабируемость в обходном пути, так что даже если то, что вы делаете в блоке try, является более сложным, чем назначая строку, вы должны иметь возможность безопасного доступа к данным из вашего блока catch.
Вместо локальной переменной может быть объявлено публичное свойство; это также должно избегать другой потенциальной ошибки неназначенной переменной. public string S {get; задавать; }
В Python они видны в блоках catch / finally, если строка, объявляющая их, не выбрасывает.
Когда вы объявляете локальную переменную, она помещается в стек (для некоторых типов все значение объекта будет в стеке, для других типов в стек будет только ссылка). Когда в блоке try есть исключение, локальные переменные в блоке освобождаются, что означает, что стек «разворачивается» обратно в состояние, в котором он находился в начале блока try. Это по дизайну. Это то, как try / catch способен отступать от всех вызовов функций внутри блока и возвращает вашу систему в функциональное состояние. Без этого механизма вы никогда не сможете быть уверены в состоянии чего-либо, когда возникает исключение.
Наличие вашего кода обработки ошибок зависит от внешних объявленных переменных, которые имеют свои значения, измененные внутри блока try, кажется мне плохим дизайном , То, что вы делаете, по сути направляет ресурсы намеренно, чтобы получить информацию (в данном случае это не так уж плохо, потому что вы только утечка информации, но представьте, если бы это был какой-то другой ресурс? Вы просто делаете жизнь сложнее на себе в будущее). Я бы предложил разбить ваши блоки try на более мелкие куски, если вам нужна более гранулированность при обработке ошибок.
Ответ, как отмечали все, в значительной степени «вот как определяются блоки».
Есть несколько предложений, чтобы сделать код более красивым. См. ARM
try (FileReader in = makeReader(), FileWriter out = makeWriter()) {
// code using in and out
} catch(IOException e) {
// ...
}
Предполагается, что исправления также будут устранены.
with(FileReader in : makeReader()) with(FileWriter out : makeWriter()) {
// code using in and out
}
UPDATE: ARM реализована в Java 7. http://download.java.net/jdk7/docs/technotes/guides/language/try-with-resources.html
Часть причин, по которым они не находятся в той же области, состоит в том, что в любой точке блока try вы можете исключить исключение. Если они были в одном и том же объеме, это была катастрофа в ожидании, потому что в зависимости от того, где было выбрано исключение, это может быть еще более неоднозначным.
По крайней мере, когда объявлено за пределами блока try, вы знаете наверняка, какая переменная могла бы быть минимальной, когда генерируется исключение; Значение переменной перед блоком try.