Подтвердить что ты не робот

Почему я не могу использовать ключевое слово as для структуры?

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

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 дает следующую ошибку времени компиляции:

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

В чем смысл этого? И как я могу его решить?

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

Однако вы можете использовать as со значениями типов... если они имеют значение nullable:

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 переменной типа ссылочного типа (или нулевому типу значений), но не к типу значения, не имеющему значения NULL.

Ответ 3

Из С# Spec

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

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

Ответ 4

Call? call = line.Tag as Call?;

Ответ 5

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

Вы должны заменить свое использование как на два: 'is' и 'as'

if (line.Tag is Call) {
  call = (Call)line.Tag;
} else {
  // Do whatever you would do if as returned null.
}

Ответ 6

В чем смысл: как указано, структуры являются типами значений.

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

Call call = line.Tag;