switch语句:“预期值为常量”

时间:2012-01-25 15:00:46

标签: c# switch-statement

目前我正在与那个“神奇的弦乐”问题作斗争:

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%是通用的。这些是在switch语句的default中处理的。除了明确确定案例值的价值之外,还有其他方法吗?

请不要争论这种方法的意义。我刚刚写了这个以更简单的方式来说明我的问题

5 个答案:

答案 0 :(得分:11)

只需使用if

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

您甚至不需要比较类型名称,而是直接比较Type个对象(引用)。

答案 1 :(得分:6)

我建议您使用规范§8.7.2,其中规定了switch-label的语法:

switch-label:
    case constant-expression:
    default:

简单地说,case标签在编译时必须是常量。请注意,typeof(MyDataField).ToString()不是编译时常量(它可能看起来不变,但不是因为它在编译时无法完全评估)。规范的第7.19节非常清楚地说明了常量是什么

您需要将其重新编码为if/else if/else

答案 2 :(得分:1)

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;
        }

答案 3 :(得分:1)

使用C#7的新pattern matching feature,我会用以下方式解决它。

这是一个简单的FieldDocument

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的列表进行任意更改

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));
}

答案 4 :(得分:0)

使用函数重载,也许是dynamic关键字。或使用访客模式。无论哪种方式都可以根据变量的运行时类型进行调度。