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

Sam*_*Sam 2 c# types switch-statement .net-4.5

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

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

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

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

Sco*_*ain 5

C#6正在引入一个功能来解决这个确切的问题,nameof表达式.

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 Code Online (Sandbox Code Playgroud)

Run Example

FooBar引用的nameof都是类型,如果重命名类中的任何自动重构工具也将取代型的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

UPDATE:nameof不返回名称空间仅使用类型名称的全名,其中Type.ToString()包含名称空间.所以也许这不会奏效.


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

以下代码假定您在名为Foo和的类的同一解决方案中有一个名为DataTrasferObjects的项目Bar

<#@ 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() #>";
}
Run Code Online (Sandbox Code Playgroud)

注意,您需要配置构建服务器以自动重新生成每个构建的代码.