switch 语句:“期望一个常量值”

发布于 2024-12-29 04:48:24 字数 814 浏览 2 评论 0原文

目前,我正在与“神奇字符串”问题作斗争:

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

现在我收到了我在线程标题中编写的错误消息。我认为问题在于这个字符串在“非编译时”时不是常量。因此,询问 switch 的唯一可能方法是通过显式确定该 case 字符串的值。我的问题是,如果我重命名 MyDataField 类,我不会收到编译错误。所以无论如何,这些类中的 90% 都是通用的。这些在 switch 语句的 default 中处理。除了明确确定 case 值之外,是否还有其他方法?

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

Currently I'm fighting with that "magical strings" issue:

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

Now I get the error Message I've written in the title of my thread. I think the problem is that this string is not a constant while "non-compile-time". So the only possible way to ask switch this is via explicitly determining the value of that case string. My problem just is that I don't get an compile error in case I'd rename the MyDataField class. So 90% of these classes are generic anyway. These are handled in the default of the switch statement. Isn't there another way than explicitly determining the value of the case value?

Please don't argue about the sense of this method. I've just written that to illustrate my problem in an easier way

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

哽咽笑 2025-01-05 04:48:24

只需使用 if

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

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

Just use an if:

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

You even don't need to compare type names, but the Type objects (references) directly.

ゃ人海孤独症 2025-01-05 04:48:24

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

switch-label:
    case constant-expression:
    default:

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

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

I refer you to the specification §8.7.2 which states for the grammar of a switch-label:

switch-label:
    case constant-expression:
    default:

Simply put, the case labels must be constants at compile-time. Note that typeof(MyDataField).ToString() is not a compile-time constant (it might look constant to you, but it's not because it can not be fully evaluated at compile time). §7.19 of the specification spells out very clearly what a constant is

You need to recode this as an if/else if/else.

冷︶言冷语的世界 2025-01-05 04:48:24

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

the case statement requires a constant value, so where you have

 case MyDataField.GetType().ToString():

you would need to change that to the specific string that you are looking for:

case "BR549":
     break;

if you are trying to determine the field type, you can do something like this:

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;
        }
别挽留 2025-01-05 04:48:24

使用新的模式匹配功能 的 C# 7 我将通过以下方式解决它。

这里是一个简单的 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));
}

With the new pattern matching feature of C# 7 I would solve it in the following manner.

Here a simple Field and Document class

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

And here a FieldOperator class which does some arbitrary changes to a list of Fields

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

Testing for correctness of these "operations"

[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));
}
岛徒 2025-01-05 04:48:24

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

Use function overloading, and maybe the dynamic keyword. Or use the Visitor pattern. Either way gives you dispatch based on the runtime type of a variable.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文