оператор switch: «ожидается постоянное значение» - PullRequest
2 голосов
/ 25 января 2012

В настоящее время я борюсь с проблемой "волшебные струны":

public class MyDataField
{
    // class definition
}

// exuecuted method
public void SwitchMultipleDataFields()
{
    var myField = new MyDataField();
    switch(myField.GetType().ToString())
    {
        // only case, which works
        case "MyDataField":
            // case operations
            break;

        // other option:
        case typeof(MyDataField).ToString():
            // case operations
            break;

        // other cases of other FieldTypes
    }
}

Теперь я получаю сообщение об ошибке, которое я написал в заголовке моей ветки. Я думаю, проблема в том, что эта строка не является константой в то время как "время некомпиляции". Таким образом, единственный возможный способ задать переключение это через явное определение значения этой строки регистра. Моя проблема только в том, что я не получаю ошибку компиляции в случае, если я переименую класс MyDataField. Так что 90% этих классов в любом случае являются общими. Они обрабатываются в default оператора switch. Нет ли другого способа, кроме явного определения значения значения дела?

Пожалуйста, не спорьте о смысле этого метода. Я только что написал это, чтобы проиллюстрировать мою проблему более простым способом

Ответы [ 5 ]

11 голосов
/ 25 января 2012

Просто используйте if:

Type type = myField.GetType();
if (type == MyDataField.GetType())
{
    …
}
else if (type.ToString() == "MyDataField")
{
    …
}
else
{
    …
}

Вам даже не нужно сравнивать имена типов, а только Type объекты (ссылки) напрямую.

6 голосов
/ 25 января 2012

Я отсылаю вас к спецификации §8.7.2, в которой говорится о грамматике switch-label:

switch-label:
    case constant-expression:
    default:

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

. Вам необходимо перекодировать это как if/else if/else.

1 голос
/ 08 мая 2017

С новой функцией сопоставления с образцом в C # 7 я бы решил ее следующим образом.

Здесь простой Field и Document класс

public class Field
{
    public string Label { get; set; }
}

public class Field<T> : Field
{
    public T Value { get; set; }
}

public class Document
{
    public string Content { get; set; }
}

А здесь класс FieldOperator, который вносит некоторые произвольные изменения в список Field s

public static class FieldOperator
{
    public static void Operate(Field[] fields)
    {
        foreach (var field in fields)
        {
            field.Label = field.GetType().ToString();
            switch (field)
            {
                case Field<Document> docField:
                    docField.Value.Content = "Foo Bar";
                    break;
                case Field<int> intField:
                    intField.Value = 600842;
                    break;
                default:
                    field.Label = "Oops";
                    break;
            }
        }
    }
}

Проверка правильности этих "операций"

[Test]
public void OperationsAreCorrect()
{            
    var docField = new Field<Document> {Value = new Document {Content = "Hello World"}};
    var intField = new Field<int> {Value = 17};
    var dateField = new Field<DateTime>();
    FieldOperator.Operate(new Field[] {docField, intField, dateField});

    Assert.IsTrue(docField.Label == docField.GetType().ToString());
    Assert.IsTrue(intField.Label == intField.GetType().ToString());
    Assert.IsTrue(dateField.Label == "Oops");

    Assert.IsTrue(docField.Value.Content == "Foo Bar");
    Assert.IsTrue(intField.Value == 600842);
    Assert.IsTrue(dateField.Value == default(DateTime));
}
1 голос
/ 25 января 2012

для оператора case требуется постоянное значение, поэтому если у вас есть

 case MyDataField.GetType().ToString():

вам нужно изменить это на конкретную строку, которую вы ищете:

case "BR549":
     break;

если вы пытаетесь определить тип поля, вы можете сделать что-то вроде этого:

Int16 bob = 5;
TypeCode objType = (TypeCode) Enum.Parse(typeof(TypeCode), bob.GetType().ToString());

        switch (objType)
        {
            case TypeCode.DateTime:
                txtResults.Text = "  - bob is a DateTime.";
                break;
            case TypeCode.Int16:
                txtResults.Text = " - bob is an int16.";
                break;
            default:
                txtResults.Text = " - bob is an unknown type.";
                break;
        }
0 голосов
/ 25 января 2012

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

...