2010-12-09 3 views
19

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

The operator as must be used within a reference type or nullable type

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

+6

Почему вы создали такую ​​структуру? Смещаемые структуры - плохая идея. – 2010-12-09 17:50:48

+2

@Mark: +1 И структура просто собирается получить коробку для хранения в свойстве Tag в любом случае ... – cdhowie 2010-12-09 17:59:32

+1

Хм, это не обязательно быть изменчивым. Но я думаю, что я должен улучшить класс для этой цели. – 2010-12-09 18:30:44

ответ

30

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

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

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

+1

Невозможно присвоить значение null, если сбой отказа - это ключ! +1 – 2010-12-09 17:44:14

0

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

Вы должны заменить использование, как и два: «есть» и «как»

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

Я бы не назвал это «ограничением» C#, что заставляет его звучать как что-то, что должно быть исправлено. Это * ограничение *, которое естественно, основываясь на том, что должен делать оператор as. – 2010-12-09 17:51:36

+0

Может быть. Были и другие допустимые расчетные точки. C# 1.0 может заставить выражение «x as T» возвращать значение по умолчанию (T), если x не было явно конвертировано в T. С введением типов с нулевым значением C# мог бы сделать возвращаемый тип 'x as T' Nullable , когда T это тип значения. – 2010-12-09 21:31:28

30

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

-1

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

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

Call call = line.Tag; 
12

От C# Spec

§7.10.11 The as operator is used to explicitly convert a value to a given reference type or nullable type. Unlike a cast expression (§7.7.6), the as operator never throws an exception. Instead, if the indicated conversion is not possible, the resulting value is null.

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

Смежные вопросы