在编译时为 switch case 生成 const 字符串
Generate const strings at compile time for switch cases
我们在 .net 4.5(重要)的遗留代码中有一个静态 class,它定义了许多对象类型的常量字符串值(意味着 x.GetType().ToString()
的值)主要用于开关语句。
这尤其糟糕,因为某些重构会破坏所有这些 switch 语句,而且使用它的地方非常多,我们无法更改它。如果我现在写的话,我知道其他解决方案,但是:
有什么方法可以在不更改 switch 语句的情况下定义类型的 const 字符串以获取编译时类型,因为我在编译时拥有我需要的所有信息。
我知道 switch 语句在编译时被编译成查找 table 并且不计算 cases 中的表达式,但是有什么方法可以在编译时定义一个 const 值吗?我唯一能想到的就是在构建之前动态生成代码。还有其他解决办法吗?
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 {}
nameof
中引用的Foo
和Bar
是类型,如果重命名class任何自动重构工具也会替换[=中的类型13=].
编辑:没有捕捉到 "do not modify the switch" 部分,您也可以将其与常量字符串一起使用。
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
不 return 带命名空间的全名只有类型名称,其中 Type.ToString()
确实包括命名空间。所以也许这行不通。
如果您不能使用 C# 6,另一种选择是使用 T4 Text templates 为您的 switch 语句动态构建常量。唯一的问题是保存您引用的类型的程序集不能存在于您生成代码的同一程序集中。
以下代码假定您在同一解决方案中有一个名为 DataTrasferObjects 的项目,其中 classes 名为 Foo
和 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() #>";
}
请注意,您将需要 configure your build server 在每次构建时自动重新生成代码。
我们在 .net 4.5(重要)的遗留代码中有一个静态 class,它定义了许多对象类型的常量字符串值(意味着 x.GetType().ToString()
的值)主要用于开关语句。
这尤其糟糕,因为某些重构会破坏所有这些 switch 语句,而且使用它的地方非常多,我们无法更改它。如果我现在写的话,我知道其他解决方案,但是:
有什么方法可以在不更改 switch 语句的情况下定义类型的 const 字符串以获取编译时类型,因为我在编译时拥有我需要的所有信息。
我知道 switch 语句在编译时被编译成查找 table 并且不计算 cases 中的表达式,但是有什么方法可以在编译时定义一个 const 值吗?我唯一能想到的就是在构建之前动态生成代码。还有其他解决办法吗?
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 {}
nameof
中引用的Foo
和Bar
是类型,如果重命名class任何自动重构工具也会替换[=中的类型13=].
编辑:没有捕捉到 "do not modify the switch" 部分,您也可以将其与常量字符串一起使用。
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
不 return 带命名空间的全名只有类型名称,其中 Type.ToString()
确实包括命名空间。所以也许这行不通。
如果您不能使用 C# 6,另一种选择是使用 T4 Text templates 为您的 switch 语句动态构建常量。唯一的问题是保存您引用的类型的程序集不能存在于您生成代码的同一程序集中。
以下代码假定您在同一解决方案中有一个名为 DataTrasferObjects 的项目,其中 classes 名为 Foo
和 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() #>";
}
请注意,您将需要 configure your build server 在每次构建时自动重新生成代码。