невозможно преобразовать тип 'string' в 'int?' через преобразование ссылок, преобразование в бокс, преобразование в распаковку, преобразование с переносом или преобразование нулевого типа - PullRequest
7 голосов
/ 20 мая 2009

C # принимает следующее:

object o = "hello";
int? i = o as int?;

if (i == null) {
    // o was not a boxed int
}
else {
    // Can use i.Value to recover the original boxed value
}

но не

String o = "hello";
int? i = o as int?;

if (i == null) {
    // o was not a boxed int
}
else {
    // Can use i.Value to recover the original boxed value
}

Мне просто интересно поведение ключевого слова as в C #.

Так же, как в Java, это не получится:

Object test1 = "hello";
Integer test2 = (Integer) test1;
String test3 = "hello";
Integer test4 = (Integer) test3; //compilation error

Ответы [ 5 ]

18 голосов
/ 20 мая 2009

Компилятор знает, что строка никогда не может быть int?, поэтому он говорит вам об этом. Это не значит, что int? бесполезно. Ваш попытанный вариант использования далек от нормального. Нормальным является «Я хочу представить целое число и вероятность того, что значение отсутствует / неизвестно». Для этого int? работает очень хорошо.

С чего бы вам ожидать, что ваш оригинальный код будет работать? Почему это будет полезно?

Обратите внимание, что вы можете использовать as с обнуляемыми типами для распаковки:

object o = "hello";
int? i = o as int?;

if (i == null)
{
    // o was not a boxed int
}
else
{
    // Can use i.Value to recover the original boxed value
}

РЕДАКТИРОВАТЬ: увидев ваш комментарий, вы не используете as для разбора вещей. Вы, вероятно, хотите использовать int.TryParse:

string text = "123":
int value;
if (int.TryParse(text, out value))
{
    Console.WriteLine("Parsed successfully: {0}", value);
}
else
{
    Console.WriteLine("Unable to parse text as an integer");
}

Если вы уверены, что строка должна быть целым числом (т. Е. В противном случае это ошибка), тогда вы можете просто использовать int.Parse:

int value = int.Parse(text);

Это вызовет исключение, если синтаксический анализ завершится неудачей.

Обратите внимание, что оба эти метода позволяют вам указать поставщика формата (обычно это информация о культуре), который позволяет вам выразить, как числа выражаются в этом формате (например, разделители тысяч).

РЕДАКТИРОВАТЬ: В ответ на ваш новый вопрос, компилятор предотвращает это, потому что он знает, что строка не может возможно быть упакованным int - преобразование никогда не будет успешным. Когда ему известно только, что исходное значение является объектом, оно может успешно.

Например, предположим, я сказал вам: "Вот форма: это квадрат?" Это разумный вопрос. Разумно спросить: вы не можете сказать, не глядя на форму.

Если, однако, я сказал: "Вот треугольник: это квадрат?" Тогда вы будете иметь право смеяться мне в лицо, поскольку треугольник не может быть квадратом - вопрос не имеет смысла.

2 голосов
/ 20 мая 2009

INT? означает обнуляемый целочисленный тип, а не int, который может содержать переменные любого другого типа.

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

INT? позволяет хранить любое целочисленное значение или нулевое значение. Что полезно, когда говорят, что ответ на вопрос «Сколько заказов разместил этот человек» на законных основаниях означает «я не знаю», а не количество заказов, или ноль, который будет «Я знаю, что этот человек никогда разместил заказ ".

1 голос
/ 25 июня 2009

Я хочу добавить дополнительную информацию.

Другой случай, когда приведение неверно и компилятор выдает ошибку при компиляции, это то, что System.String помечается как загерметизированный . Таким образом, компилятор знает, от каких типов System.String наследуются и к каким типам вы можете привести строку, используя как -оператор.

Из-за ключевого слова загерметизировано компилятор также знает, что вы не можете наследовать от System.String , чтобы добавить функциональность или реализовать некоторые дополнительные интерфейсы.

Приведенный ниже код является примером, и компилятор выдаст следующую ошибку при компиляции

Невозможно преобразовать тип SealedClass в 'ICastToInterface' через ссылку конвертация, конвертация бокса, распаковка конвертация, упаковка преобразование или преобразование нулевого типа

public class UnsealedClass {
  // some code
}

public sealed class SealedClass {
  // some code
}

public interface ICastToInterface {
  // some code
}

public class Test {

  public Test() {
    UnsealedClass unsealedClass = new UnsealedClass();

    SealedClass sealedClass = new SealedClass();

    ICastToInterface unsealedCast = unsealedClass as ICastToInterface;  // This works fine

    ICastToInterface sealedCast = sealedClass as ICastToInterface; // This won´t compile, cause SealedClass is sealed
  }
}
0 голосов
/ 20 мая 2009

INT? является обнуляемым целым числом, оно не имеет ничего общего с приведением типов и ключевым словом as. «String» - это объект строкового типа, который не может быть преобразован в int (обнуляемый или не обнуляемый).

Ключевое слово as практически совпадает с приведением с использованием скобок, за исключением того, что оно не вернет ошибку, а установит объект в null:

int i = 1;

object o = i; //boxing

int j = (int)o; //unboxing

Этот первый пример работает, поскольку объект, назначенный o, является int.

Теперь рассмотрим:

string i = "MyString";

object o = MyString;

 int j = (int)o //unboxing raises exception

 int j = o as int; //raises compilation Error as int is not nullable
 int? j = o as int?; /// o == null

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

Richard

0 голосов
/ 20 мая 2009

но вы можете проверить значение null и установить его в null.

int? blah;
if (blah == null)
{}
...