проблема «вне» в VB.NET

Когда в C# у нас есть параметры параметров out и ref, в VB есть только один: ByRef.

Теперь небольшая «проблема» при попытке «устранить» предупреждение компилятора о том, что тест не был инициализирован перед передачей в качестве аргумента:

Dim test As MyParsableClass ' = Nothing  need imperatively?? '
' some code ... '
MyParsableClass.TryParse("value", test) ' warning on "test" here

краткое объявление класса:

Class MyParsableClass

  Public Shared Function TryParse(ByVal value As String, _
    ByRef myParsableClass As MyParsableClass) As Boolean
    myParsableClass = Nothing
    If True Then
      ' parse code OK'
      myParsableClass = New MyParsableClass()
      Return True
    Else
      ' parse code NOK '
      ' myParsableClass remains Nothing '
      Return False
    End If

  End Function

End Class

возможно, решение состояло в том, чтобы объявить

...Optional ByRef myParsableClass As MyParsableClass = Nothing)

но я не могу установить этот параметр как необязательный. Что будет, если я пропущу это?

PS (изменить)

В реальном проекте мой "анализируемый" класс - это MyHour со свойствами Hour и Minute. Я уже написал Parse(value as String) с FormatException, но я думаю, что код мог бы быть более понятным, компактным и быстрым, когда я не буду использовать блоки try catch...


person serhio    schedule 18.01.2010    source источник
comment
В чем именно заключается ваш вопрос?   -  person Dirk Vollmar    schedule 18.01.2010
comment
@divo: Как убрать предупреждение (без #pragma и прочих подобных уловок)?   -  person serhio    schedule 18.01.2010
comment
Так есть ли проблема, когда вы инициализируете локальную переменную с помощью Nothing?   -  person Dirk Vollmar    schedule 18.01.2010
comment
нет, но VB.NET выглядит ограниченным с этой точки зрения   -  person serhio    schedule 18.01.2010
comment
@divo: Да, но когда я работал над проектами C#, я всегда пытался писать код с 0 предупреждениями и 0 ошибками.   -  person serhio    schedule 18.01.2010
comment
@serhio - как вы и divo оба упомянули, здесь есть способ закодировать с 0 предупреждениями и 0 ошибками - выполнить назначение Nothing. В разных языках есть разные заклинания вуду, чтобы успокоить составителей.   -  person Damien_The_Unbeliever    schedule 18.01.2010


Ответы (2)


Я не верю, что это предупреждение можно предотвратить без явного присваивания.

Разные языки имеют разные функции/возможности - иначе был бы только один язык программирования :-) В этом случае, да, VB не делает вид, что существует два типа параметров ref, как это делает C# - так что что касается CLR, "out" не существует.

И я не уверен, о чем говорит peSHIR - TryParse был добавлен в более поздние выпуски BCL именно для ситуации, когда синтаксический анализ может завершиться неудачно, так что вы можете принять ошибку path, не требуя создания исключения.

Изменить

Чтобы добавить - причина, по которой вы не получаете предупреждение для многих встроенных типов, для которых существует TryParse (например, Int32), заключается в том, что они являются типами Structs/Value и, следовательно, всегда имеют значение. Если ваш класс достаточно прост, было бы логично, если бы вместо этого он был структурой?

person Damien_The_Unbeliever    schedule 18.01.2010
comment
как я уже упоминал, (настоящий) класс MyHour может быть действительно структурой... это интересная идея. - person serhio; 18.01.2010
comment
Я не могу объявить MyHour как структуру... там используются необязательные параметры. Необязательные параметры не могут быть структурами. - person serhio; 18.01.2010
comment
Также структуры не могут иметь ни конструкторов без параметров, ни защищенных членов, их члены не могут быть инициализированы при объявлении, я не могу реализовать IComparable с Equals (объектом) и т. д. и т. д. - person serhio; 18.01.2010
comment
Ах, вот почему я спросил, будет ли это логично - очевидно, я не знал, какие дополнительные ограничения у вас есть на вашу реализацию - хотя (в конкретном случае) необязательные параметры могут быть лучше обработаны как NUllable‹T› или перегрузки - это удобнее для языков, отличных от VB. - person Damien_The_Unbeliever; 18.01.2010
comment
Было неплохо добавить что-то вроде TryParse (как вариант, чтобы всегда получать Exception на Parse), но то, как это было реализовано (=использование параметра out), многие люди считают плохим решением. Microsoft находится в этом лагере, поэтому вы получаете предупреждение, о котором спрашивал Серхио. - person peSHIr; 21.01.2010

Не совсем ответ на ваш вопрос, но out и ref/ByRef плохие, так зачем вообще их использовать? Многие разработчики считают, что парадигма TryParse в .NET Framework 1.0 была плохим путем.

Почему бы не использовать MyParsableClass, у которого есть метод Public Shared Function Parse(ByVal value As String) As MyParsableClass, который при необходимости вызывает соответствующее исключение?

Или даже Public Shared Function Parse(ByVal value As String) As MyParsableClassParsed, где MyParsableClassParsed — это вспомогательный внутренний класс, который содержит два свойства только для чтения: Success As Boolean и Result As MyParsableClass? Тогда вы всегда можете получить результат от вызова Parse, но вы получите Success==True и Result==[whatever] или просто Success==False и Result==Nothing.

Кроме того, ваш вспомогательный класс MyParsableClassParsed может также использовать перечислитель вместо логического значения и/или списка сообщений об ошибках, чтобы сообщить вызывающей стороне, как/почему операция синтаксического анализа не удалась. Или исключение throw может иметь такое перечисляемое значение и/или сообщения об ошибках.

Гораздо проще в использовании и более гибкий. И все без ByRef, чтобы дать вам головную боль/предупреждения.

person peSHIr    schedule 18.01.2010
comment
на самом деле мой анализируемый класс - это MyHour со свойствами Hour и Minute. Это будет не очень ясно, если я добавлю также свойства Success и Result... Я уже написал Parse(value as String) с FormatException, но код становится более понятным, компактным и быстрым, когда я не использую блоки try catch... - person serhio; 18.01.2010
comment
Просто указываю, что все объекты, не производные от System.ValueType, обрабатываются ByRef неявно, т. е. ваш класс является ByRef независимо от того, указываете ли вы его в списке параметров метода или нет. - person invert; 18.01.2010
comment
@Monkey: ты ошибаешься. ByRef может ни на что не указывать внешнюю ссылку внутри вызывающего метода, ByVal не может. - person serhio; 18.01.2010
comment
@Monkey: все параметры передаются ByVal по умолчанию, даже ссылочные типы. Единственные временные параметры передаются по ссылке, когда используется ключевое слово ByRef. - person Chris Dunaway; 19.01.2010
comment
@serhio: Ах, для такого простого случая (я предполагал более сложный синтаксический анализ), вы, вероятно, определили MyHour как Struct (а не Class, и вы могли бы определить для него TypeConverter. См. stackoverflow.com/questions/1866552/1866620#1866620 - person peSHIr; 19.01.2010
comment
@peSHIR: уже обсуждалось. См. комментарии Damien_The_Unbeliever. - person serhio; 19.01.2010