2017-01-05 5 views
0

Я пытаюсь сделать это:Почему typeof (int) .ToString() не является константой?

const string intType = typeof(int).ToString(); 
switch (typeof(MyT).ToString()) 
{ 
    case intType: 
    { 
     return "int"; 
     break; 
    } 
    ... 
} 

Но компилятор говорит:

ошибка CS0133: выражение, которое присваивается 'intType' должна быть постоянной

Как я знаю , typeof Оператор работает во время компиляции. Итак, что случилось?

+5

'ToString()' является метод, называемый во время выполнения. –

+2

Даже 'typeof (int)' не будет возвращать значение const. Методы не гарантируют возвращаемое значение const. –

+0

Возможно, вы захотите использовать 'readonly' вместо' const' и, возможно, посмотрите на 'Type' вместо' string'. –

ответ

11

Как я знаю, оператор typeof работает во время компиляции.

Вы не знаете что из-за знания должен быть истинным. Откуда у вас возникла идея, что во время компиляции выполняется typeof? Он создает непостоянный объект. И тогда нет никакой гарантии, что ToString не производит отдельную строку при каждом запуске, поэтому ее нельзя рассматривать как константу.

Итак, что случилось?

Вы рассуждаете о ложном убеждении.

Спецификация C# четко описывает условия, которые должны выполняться для того, чтобы выражение являлось константой времени компиляции. Эти условия включают выражение, не содержащее никакого оператора или вызова метода typeof.

Но здесь есть гораздо большие проблемы. Я предполагаю, что MyT является типичным параметром типа, что означает, что вы пытаетесь включить значение параметра общего типа. Это почти всегда неправильно.

Что вы действительно пытаетесь сделать? Какую проблему вы действительно пытаетесь решить? Поскольку этот код, который вы показали до сих пор, указывает на то, что вы идете по непродуктивному пути решения любой реальной проблемы.

+0

Да, @ user1234567 - что вы * на самом деле пытаетесь сделать? –

+0

@ Эрик, извините за мою неточность в терминах и спасибо за ответ. Я новичок в C#. И моя картина о 'typeof' (то, что я назвала« знаю ») опирается на поверхностный обзор некоторых ответов на относительные вопросы. И похоже, что 'typeof' дает тип времени компиляции в отличие от' GetType' (который дает тип времени выполнения).Итак, подумал, нет никаких оснований откладывать на временное изъятие типа времени компиляции. – user1234567

+4

@ user1234567: Ах, теперь я вижу источник вашего смятения; Спасибо за разъяснения. Да, 'GetType' возвращает тип *, известный для среды выполнения * объекта, а' typeof' принимает в качестве своего операнда a *, известного для типа компилятора *. Но это не означает, что операция * выполняется * во время компиляции, что является необходимым для того, чтобы выражение было константой. Выражение 'typeof 'создает объект типа' Type', который является объектом времени выполнения. –

1

Я думаю, совершенно очевидно, что он хочет добиться:

Он хочет, чтобы проверить тип равенства в switch-case вместо через if-elseif. И если честно, почему бы и нет? Но как он может это достичь?

  1. Первый вариант: Ждите C# 7.0. Да, такое дерьмо в будущем возможно!

  2. Второй вариант: использовать строки. Но строки case должны быть постоянными. Так как насчет чудесного nameof?

Я просто попробовал эту «красоту», и это работает, так что, возможно, это решит вашу проблему:

switch (typeof(Int32).Name) 
{ 
    case nameof(Int32): 
     Console.WriteLine("It's an Int32!"); 
     break; 
    case nameof(Double): 
     Console.WriteLine("It's a Double"); 
     break; 
} 
+1

Это приятное использование 'nameof', но я все еще думаю, что здесь есть большая проблема: если вы вообще делаете переключатель типа *, что-то, вероятно, не так с дизайном. Существует почти всегда лучший способ решить проблему, чем включение типа. –

+4

Кроме того, я хочу отметить, что ваше решение предполагает, что типы не соответствуют их пространствам имен. Вы не могли бы, например, иметь «case nameof (Foo.Bar): ... case nameof (Blah.Bar):' потому что оба будут '' Bar "'. –

+0

Да, конечно. Я знаю, это всего лишь обходной путь, и вы всегда должны проверить, требуется ли вам сравнение типов __real__. К счастью, с C# 7.0 не будет необходимости в этом обходном пути. –

2

Единственный способ сравнения типа MyT с известными типами, проверяя их объекты типа для равенства ,Это может быть сделано следующим образом:

if (typeof(MyT) == typeof(int)) return "int"; 
if (typeof(MyT) == typeof(decimal)) return "decimal"; 
// etc... 

Вы не можете использовать этот подход в switch, потому что (на данный момент) а switch требует, чтобы элемент проверяется имеет простой тип:

switch (typeof(T)) // Compile error: "switch expression or case label must be a bool, 
        // char, string, integral, enum, or corresponding nullable type" 
{ 
    case typeof(int): return "int"; 
    case typeof(decimal): return "decimal"; 
    // ... 
} 

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

E.g. вместо MyMethod<MyT>(MyT item) с проверками типа для MyT, рассмотреть вопрос о внесении MyMethod(int item), MyMethod(decimal item) и т.д.

-1

Если вы просто пытаетесь получить строку, описывающую тип объекта, вам просто нужно позвонить .GetType() вместо этого.

Например, небольшая функция, которая вернет имя строки типа объекта.

static string GetTypeString(object obj) 
{ 
     return obj.GetType().FullName; 
} 

Это вернется к полному пути к объекту. В случае int, он вернет System.Int32. Если вы хотите только часть Int32, используйте GetType(). Вместо имени.

Кроме того, вам не нужно иметь перерыв; в переключателе, если у вас есть возврат;

Если у вас есть определенный код, который должен быть запущен для некоторых типов или конкретная строка, которую вы хотите вернуть, вы можете использовать строку для значений, возвращаемых приведенным выше. Например:

static string GetSimpleType(object obj) 
    { 
     var stringRepresentation = GetTypeString(obj); 
     switch (stringRepresentation) 
     { 
      case "System.Int64": 
      case "System.Int32": 
       return "int"; 

      default: 
       return stringRepresentation; 
     } 
    } 

по умолчанию является уловкой всех в операторах switch для всего, что не имеет случая. Подумайте об этом, как о другом.

В приведенном выше примере мы возвращаем то же значение для int, Int32 и Int64. Ярлыки case могут просачиваться на другие ярлыки, если они пусты.

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

Наконец, если вы сравниваете типы, если и если еще работает лучше:

 static string GetSimpleType(object obj) 
     { 
      if (obj.GetType() == typeof(int)) 
      { 
       return "int"; 
      } 

      return obj.GetType().ToString(); 
     } 
Смежные вопросы