Почему я не могу использовать ключевое слово as для структуры? - PullRequest
23 голосов
/ 09 декабря 2010

Я определил следующую структуру:

public struct Call
{
    public SourceFile caller;
    public SourceFile callee;

    public Call(SourceFile caller, SourceFile callee)
    {
        this.caller = caller;
        this.callee = callee;
    }
}

Позже я назначаю его свойству Tag другого объекта:

line.Tag = new Call(sf1, sf2);

Но когда я пытаюсь получить свойство Tag следующим образомИтак,

Call call = line.Tag as Call;

Visual Studio выдает следующую ошибку во время компиляции:

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

Что это значит?И как мне это решить?

Ответы [ 6 ]

34 голосов
/ 09 декабря 2010

Некоторые из существующих ответов не вполне правильно.Вы не можете использовать ненулевые типы с as, потому что результатом as является нулевое значение типа, если первый операнд фактически не имеет подходящего типа.

Тем не менее, вы можете использовать as с типами значений ... если они могут быть обнуляемыми:

int a = 10;
object o = a;

int? x = o as int?; // x is a Nullable<int> with value 10
long? y = o as long?; // y is a Nullable<long> with the null value

Таким образом, вы можете использовать:

Call? call = line.Tag as Call?;

Тогда вы можете использовать его как:

if (call != null)
{
    // Do stuff with call.Value
}

Два предостережения:

  • По моему опыту, это медленнее, чем просто использование is
  • Вы должны серьезно пересмотреть свой текущий Call тип:
    • Он предоставляет открытые поля, что обычно является плохой инкапсуляцией
    • Это тип изменяемого значения, которыйпочти наверняка ошибка

Я настоятельно рекомендую вам сделать это классом - в этот момент эта проблема все равно исчезнет.

Другая мысль: еслитег должен всегда быть Call, тогда лучше привести его:

Call call = (Call) line.Tag;

Таким образом, если данныене соответствует вашим ожиданиям (т.е. есть какая-то ошибка, такая, что Tag не является Call), тогда вы узнаете об этом раньше, а не после того, как вы потенциально сделали какую-то другую работу.Обратите внимание, что это приведение будет вести себя по-разному в зависимости от того, является ли Call структурой или классом, если Tag имеет значение null - вы можете преобразовать нулевое значение в переменную ссылочного типа (или типа значения, допускающего значение NULL), но нек необнуляемому типу значения.

33 голосов
/ 09 декабря 2010

Структура является типом значения, поэтому его нельзя использовать с оператором as. Оператор as должен иметь возможность присвоить значение null, если приведение не выполнено Это возможно только для ссылочного типа или типа значения NULL.

Есть несколько способов решить эту проблему, но лучше всего поменять тип Call со структуры на класс. Это существенно изменит ваш тип с типа значения на ссылочный тип, что позволяет оператору as присваивать значение null в случае сбоя приведения.

Для получения дополнительной информации о типах значений и ссылочных типах, , эта - достойная статья. Также посмотрите MSDN:

12 голосов
/ 09 декабря 2010

Из C # Spec

§7.10.11 Оператор as используется для явно преобразовать значение в данный ссылочный тип или обнуляемый тип . В отличие от приведенного выражения (§7.7.6), оператор as никогда не выбрасывает исключение. Вместо этого, если указанное преобразование невозможно, результирующее значение равно null .

Ссылки и обнуляемые типы могут быть нулевыми. Структуры являются типами значений, поэтому они не могут быть нулевыми.

1 голос
/ 09 декабря 2010
Call? call = line.Tag as Call?;
0 голосов
/ 09 декабря 2010

В чем смысл - Как уже говорилось, структуры являются типами значений.

Как я могу это решить - Измените его на

Call call = line.Tag;
0 голосов
/ 09 декабря 2010

Это ограничение C #. Если тип был ссылочным типом, то, если приведение не удалось, он просто вернул бы 'null', но, поскольку это тип значения, он не знает, что возвращать в случае сбоя преобразования.

Вы должны заменить использование as двумя: «is» и «as»

if (line.Tag is Call) {
  call = (Call)line.Tag;
} else {
  // Do whatever you would do if as returned null.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...