Является ли наследование от классов исключений единственным способом сделать объект «бросаемым» в C #? - PullRequest
4 голосов
/ 26 ноября 2010

Можно ли как-нибудь сделать так, чтобы мои объекты, не являющиеся исключениями, стали «бросаемыми», чтобы любые локальные переменные, объявленные в блоке try, например obj в блоке try ниже

try
{ 
   SomeObject obj = new SomeObject(); 
}catch {}

может пересечь границу области видимости в предложении catch {} ?? Я хочу использовать экземпляр obj в предложении catch {}, даже если его состояние нарушено. Возможно ли это как-то?

Возможно, возможно (?), Поскольку компилятор C # может делать то же самое (для оптимизации, я бы предположил?) И позволяет предложению catch получать любой объект System.Object, но я не могу использовать это в VS для этого метода:

public void Foo()
{

    try
    {
    }
    catch(Exception ex)
    {
    }

    try
    {
    }
    catch
    {
    }

}

генерирует этот IL:

.method public hidebysig instance void  Foo() cil managed
{
  // Code size       22 (0x16)
  .maxstack  1
  .locals init ([0] class [mscorlib]System.Exception ex)
  IL_0000:  nop
  .try
  {
    IL_0001:  nop
    IL_0002:  nop
    IL_0003:  leave.s    IL_000a
  }  // end .try
  catch [mscorlib]System.Exception 
  {
    IL_0005:  stloc.0
    IL_0006:  nop
    IL_0007:  nop
    IL_0008:  leave.s    IL_000a
  }  // end handler
  IL_000a:  nop
  .try
  {
    IL_000b:  nop
    IL_000c:  nop
    IL_000d:  leave.s    IL_0014
  }  // end .try
  catch [mscorlib]System.Object     /* <-- I want to do like this*/
  {
    IL_000f:  pop
    IL_0010:  nop
    IL_0011:  nop
    IL_0012:  leave.s    IL_0014
  }  // end handler
  IL_0014:  nop
  IL_0015:  ret
} // end of method Class::Foo

Есть ли способ (управляемый / неуправляемый) «обманывать» подобным образом и определять «бросаемое» поведение для типа SomeObject, чтобы я мог оставить за собой право наследовать от значимых классов и не должен наследовать от исключения классы просто делают объект «бросаемым»?

Как насчет того, чтобы мне это нравилось (а сейчас я это делаю):

SomeObject obj = null; 
try
{ 
   obj = new SomeObject(); 
}catch {}

снижает производительность, если obj определен внутри или снаружи предложения try, так как t выглядит так, что они оба генерируют идентичную локальную переменную хранения метода (не области действия) - вы получаете .locals init ([0] class ClassLibrary.Class obj в IL в любом случае, так Может быть, это не медленнее, если переменная никогда не инициируется? Другими словами, если у меня SomeObject obj = null; определено в любом месте внутри кода метода, но я никогда не инициализирую его как фактический экземпляр SomeObject, имеет ли значение (с точки зрения производительности), если мое переменное определение находится внутри try / catch scope или глобальный для всей области функции (не внутри try / catch)?

Ответы [ 5 ]

5 голосов
/ 26 ноября 2010

(РЕДАКТИРОВАТЬ: Извините, я только что видел, что вы предложили это прямо в конце вашего поста. В основном это правильно!)

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

SomeObject obj = null;
try
{ 
    obj = new SomeObject(); 
    // Other stuff
}
catch (IOException e) // Or whatever
{
    // Now you can refer to obj
}

Просто учтите, что obj может быть нулевым, если исключение было выдано до того, как переменной было присвоено ее новое значение (например, если конструктор SomeObject вызвал исключение).

Нет, из-за этого у вас не возникнет проблем с производительностью - по крайней мере, если есть какие-либо эффекты, они будут незначительными. Код может закончиться тем, что на самом деле выполнит дополнительное задание, но шансы на то, что это уместно, практически отсутствуют.

1 голос
/ 26 ноября 2010

Предыдущий ответ уже рекомендовал перенести объявление SomeObject obj до блока try . Если вам нужен доступ obj выше в стеке вызовов, вы можете создать подкласс Exception , который содержит свойство типа SomeObject , которое вы можете использовать пройти obj вокруг:

class SomeObjectException : Exception
{
  // Constructors here
  public SomeObject Object { get; set; }
}

и

throw new SomeObjectException { Object = obj }; 
0 голосов
/ 06 декабря 2010

Во-первых, нет, нет способа определить переменную внутри блока и получить к ней доступ вне блока. Не имеет значения, является ли это блоком try, блоком catch или чем-то еще. Блоки определяют область действия переменной, а переменные, определенные внутри блока, ограничиваются этим уровнем. А когда что-то выходит из области видимости, оно становится пригодным для сбора мусора (при условии, что число ссылок равно 0 и т. Д. И т. Д.).

Если вам нужен доступ к переменной за пределами блока, то, что вы сделали в конце, абсолютно правильно. Если вы используете try / catch, у вас гораздо больше проблем, связанных с производительностью, чем с объявлением переменной, происходящим снаружи (так как перехват включает в себя обход кадров для поиска обработчика и т. Д., И т. Д.).

То, что вы / могли / сделаете, это сгенерировали свое собственное исключение с объектом в данных. Я бы не рекомендовал это делать, так как мне непонятно, что вы хотите сделать. Если вы просто хотите убрать это, просто объявите это снаружи. Или, если вы не собираетесь ничего делать с этим исключением, ради всего святого, используйте декларацию using. Да, ваш объект должен реализовывать IDisposable, но если у вас есть код для очистки, технически вы тоже можете это сделать.

И последнее. Вы сказали:

Я хочу использовать экземпляр obj в предложении catch {}, даже если его состояние скомпрометировано.

Обратите внимание, что есть случаи, когда состояние может быть скомпрометировано, и вы не можете с этим справиться. StackOverflow, ExecutionEngineException и OutOfMemoryException все приходят на ум. Кроме того, когда вы используете многопоточный код, все ставки отключены, если вы не блокируете должным образом.

Для быстрого ознакомления с такими вещами, как управление памятью, обработка исключений и т. Д., Вы можете взглянуть на эту презентацию , которую я делал по отладке .NET с WinDBG и SOS.

0 голосов
/ 26 ноября 2010

Я не знаю другого способа вести себя как Исключение по ингриту из Исключения.Я не понимаю, зачем тебе это менять.Да, я полагаю, если вы сделаете попытку, операции будут еще более ленивыми.

0 голосов
/ 26 ноября 2010

Вам действительно нужно беспокоиться о таких проблемах с производительностью?Горлышко бутылки не будет вашей попыткой / уловкой или объявлением / инициализацией переменной.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...