为什么 typeof(int).ToString() 不是常量?
Why typeof(int).ToString() is not constant?
我正在尝试这样做:
const string intType = typeof(int).ToString();
switch (typeof(MyT).ToString())
{
case intType:
{
return "int";
break;
}
...
}
但是编译器说:
error CS0133: The expression being assigned to 'intType' must be constant
据我所知,typeof
运算符在编译时工作。那么,怎么了?
As I know, typeof operator works at compile-time.
你不知道因为知识必须正确。您从哪里得到 typeof
在编译时执行的想法?它产生一个非常量对象。然后无法保证 ToString
每次运行时不会产生不同的字符串,因此也不能将其视为常量。
So, what's wrong?
你的推理是错误的。
C# 规范清楚地描述了表达式成为编译时常量所必须满足的条件。这些条件包括不包含任何 typeof
运算符或方法调用的表达式。
但是这里还有更大的问题。我假设 MyT
是泛型类型参数,这意味着您正试图打开泛型类型参数的值。这几乎总是错误的做法。
你到底想做什么?你真正想解决什么问题?因为到目前为止您显示的这段代码表明您正在沿着一条非生产性的路径去解决任何真正的问题。
我想,很明显,他想达到的目的是:
他想在 switch-case
中检查类型相等性,而不是通过 if-elseif
。老实说,为什么不呢?但是他是怎么做到的呢?
第一个选项:等待C# 7.0。是啊,以后这样的狗屎也是有可能的!
第二个选项:使用字符串。但是 case
字符串需要保持不变。那么精彩的nameof
呢?
我刚试过这个 "beauty" 并且有效,所以也许这可以解决您的问题:
switch (typeof(Int32).Name)
{
case nameof(Int32):
Console.WriteLine("It's an Int32!");
break;
case nameof(Double):
Console.WriteLine("It's a Double");
break;
}
将类型 MyT
与已知类型进行比较的唯一方法是检查它们的类型对象是否相等。这可以按如下方式完成:
if (typeof(MyT) == typeof(int)) return "int";
if (typeof(MyT) == typeof(decimal)) return "decimal";
// etc...
您不能在 switch
中使用此方法,因为(目前)switch
要求被检查的项目是简单类型:
switch (typeof(T)) // Compile error: "switch expression or case label must be a bool,
// char, string, integral, enum, or corresponding nullable type"
{
case typeof(int): return "int";
case typeof(decimal): return "decimal";
// ...
}
此外,正如其他人所说,以这种方式检查类型几乎总是意味着可以通过应用不同的面向对象原则来改进您的方法。
例如考虑 MyMethod(int item)
、MyMethod(decimal item)
等
,而不是对 MyT
进行类型检查的 MyMethod<MyT>(MyT item)
如果您只是想获取描述对象类型的字符串,则只需调用 .GetType() 即可。
例如,下面是一个小函数,它将return对象类型的字符串名称。
static string GetTypeString(object obj)
{
return obj.GetType().FullName;
}
这将 return 到对象的完整路径。在 int 的情况下,它将 return System.Int32。如果您只想要 Int32 部分,请改用 GetType().Name。
还有,你不需要休息;如果你有一个 return;
如果您有某些类型需要 运行 的特定代码,或者您想要 return 的特定字符串,您可以在值 return 上使用字符串通过以上。例如:
static string GetSimpleType(object obj)
{
var stringRepresentation = GetTypeString(obj);
switch (stringRepresentation)
{
case "System.Int64":
case "System.Int32":
return "int";
default:
return stringRepresentation;
}
}
default 是一个 catch all in switch 语句,用于所有没有大小写的内容。把它想象成另一个。
在上面的示例中,我们return int、Int32 和 Int64 的相同值。如果案例标签为空,则案例标签可以落入其他案例标签。
您可以通过 运行 一个简单的脚本找到编写开关所需的所有值,并对字符串值进行硬编码,因为它们对于相同的类型总是相同的。如果字符串不同,则类型不同。
最后,如果要比较类型,if 和 if else 效果更好:
static string GetSimpleType(object obj)
{
if (obj.GetType() == typeof(int))
{
return "int";
}
return obj.GetType().ToString();
}
我正在尝试这样做:
const string intType = typeof(int).ToString();
switch (typeof(MyT).ToString())
{
case intType:
{
return "int";
break;
}
...
}
但是编译器说:
error CS0133: The expression being assigned to 'intType' must be constant
据我所知,typeof
运算符在编译时工作。那么,怎么了?
As I know, typeof operator works at compile-time.
你不知道因为知识必须正确。您从哪里得到 typeof
在编译时执行的想法?它产生一个非常量对象。然后无法保证 ToString
每次运行时不会产生不同的字符串,因此也不能将其视为常量。
So, what's wrong?
你的推理是错误的。
C# 规范清楚地描述了表达式成为编译时常量所必须满足的条件。这些条件包括不包含任何 typeof
运算符或方法调用的表达式。
但是这里还有更大的问题。我假设 MyT
是泛型类型参数,这意味着您正试图打开泛型类型参数的值。这几乎总是错误的做法。
你到底想做什么?你真正想解决什么问题?因为到目前为止您显示的这段代码表明您正在沿着一条非生产性的路径去解决任何真正的问题。
我想,很明显,他想达到的目的是:
他想在 switch-case
中检查类型相等性,而不是通过 if-elseif
。老实说,为什么不呢?但是他是怎么做到的呢?
第一个选项:等待C# 7.0。是啊,以后这样的狗屎也是有可能的!
第二个选项:使用字符串。但是
case
字符串需要保持不变。那么精彩的nameof
呢?
我刚试过这个 "beauty" 并且有效,所以也许这可以解决您的问题:
switch (typeof(Int32).Name)
{
case nameof(Int32):
Console.WriteLine("It's an Int32!");
break;
case nameof(Double):
Console.WriteLine("It's a Double");
break;
}
将类型 MyT
与已知类型进行比较的唯一方法是检查它们的类型对象是否相等。这可以按如下方式完成:
if (typeof(MyT) == typeof(int)) return "int";
if (typeof(MyT) == typeof(decimal)) return "decimal";
// etc...
您不能在 switch
中使用此方法,因为(目前)switch
要求被检查的项目是简单类型:
switch (typeof(T)) // Compile error: "switch expression or case label must be a bool,
// char, string, integral, enum, or corresponding nullable type"
{
case typeof(int): return "int";
case typeof(decimal): return "decimal";
// ...
}
此外,正如其他人所说,以这种方式检查类型几乎总是意味着可以通过应用不同的面向对象原则来改进您的方法。
例如考虑 MyMethod(int item)
、MyMethod(decimal item)
等
MyT
进行类型检查的 MyMethod<MyT>(MyT item)
如果您只是想获取描述对象类型的字符串,则只需调用 .GetType() 即可。
例如,下面是一个小函数,它将return对象类型的字符串名称。
static string GetTypeString(object obj)
{
return obj.GetType().FullName;
}
这将 return 到对象的完整路径。在 int 的情况下,它将 return System.Int32。如果您只想要 Int32 部分,请改用 GetType().Name。
还有,你不需要休息;如果你有一个 return;
如果您有某些类型需要 运行 的特定代码,或者您想要 return 的特定字符串,您可以在值 return 上使用字符串通过以上。例如:
static string GetSimpleType(object obj)
{
var stringRepresentation = GetTypeString(obj);
switch (stringRepresentation)
{
case "System.Int64":
case "System.Int32":
return "int";
default:
return stringRepresentation;
}
}
default 是一个 catch all in switch 语句,用于所有没有大小写的内容。把它想象成另一个。
在上面的示例中,我们return int、Int32 和 Int64 的相同值。如果案例标签为空,则案例标签可以落入其他案例标签。
您可以通过 运行 一个简单的脚本找到编写开关所需的所有值,并对字符串值进行硬编码,因为它们对于相同的类型总是相同的。如果字符串不同,则类型不同。
最后,如果要比较类型,if 和 if else 效果更好:
static string GetSimpleType(object obj)
{
if (obj.GetType() == typeof(int))
{
return "int";
}
return obj.GetType().ToString();
}