在编译时为切换案例生成const字符串

时间:2015-06-13 15:31:45

标签: c# types switch-statement .net-4.5

我们在.net 4.5(重要)遗留代码库中有一个静态类,它定义了对象类型的许多const字符串值(意味着x.GetType().ToString()的值),主要用于在switch语句中使用。

这尤其糟糕,因为某些重构会破坏所有这些switch语句,并且使用它的地方非常庞大,我们无法对其进行更改。如果我现在写它,我知道其他解决方案,但是:

有没有办法 - 没有更改switch语句 - 定义类型的const字符串以获取编译时类型,因为我在编译时需要所有信息。

我知道switch语句在编译时被编译成查找表,并且在情况下不评估表达式,但有没有办法在编译时定义一次const值?我唯一能想到的是在构建之前动态生成代码。还有其他解决方案吗?

1 个答案:

答案 0 :(得分:5)

C#6正在引入一项功能来解决这个问题,the nameof expression

using System;

public class Program
{
    public static void Main()
    {
        Test(new Foo());
        Test(new Bar());
    }

    private static void Test(object x)
    {
        switch(x.GetType().ToString())
        {
            case nameof(Foo):
                Console.WriteLine("Inside Foo's code");
            break;

            case nameof(Bar):
                Console.WriteLine("Inside Bar's code");
            break;
        }
    }
}

public class Foo {}
public class Bar {}

Run Example

Foo中引用的Barnameof是类型,如果您重命名该类,任何自动重构工具也将替换nameof中的类型。

编辑:没有赶上"不要修改开关"另外,您也可以使用常量字符串。

const string FooName = nameof(Foo);
const string BarName = nameof(Bar);

private static void Test(object x)
{
    switch(x.GetType().ToString())
    {
        case FooName:
            Console.WriteLine("Inside Foo's code");
        break;

        case BarName:
            Console.WriteLine("Inside Bar's code");
        break;
    }
}

UPDATE nameof不会返回名称空间仅使用类型名称的全名,其中Type.ToString()包含命名空间。所以这可能不起作用。

如果您不能使用C#6,另一个选择是使用T4 Text templates为您的switch语句动态构建常量。唯一的问题是保存您引用的类型的程序集不能存在于生成代码的同一程序集中。

以下代码假定您在同一解决方案中有一个名为DataTrasferObjects的项目,其中包含名为FooBar的类

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="$(SolutionDir)\DataTrasferObjects\bin\Debug\DataTrasferObjects.dll" #>
<#@ import namespace="System" #>
<#@ output extension=".cs" #>

<#
    Type fooType = typeof(DataTrasferObjects.Foo);
    Type barType = typeof(DataTrasferObjects.Bar);
#>

public static class Names
{
    public const string FooName = "<#= fooType.ToString() #>";
    public const string BarName = "<#= barType.ToString() #>";
}

注意,您需要configure your build server自动重新生成每个版本的代码。