为什么C#不允许typeof作为默认参数?

13
class MyClass
{
    public void MyMethod(Type targetType = typeof(MyClass))
    {
    }
}

typeof(MyClass)不是一个编译时常量吗?

5个回答

11

我不是IL专家,但似乎它在L_0005调用了一个方法:

return typeof(int);

它与以下内容相同:

.maxstack 1
.locals init (
    [0] class [mscorlib]System.Type typeofvar)
L_0000: ldtoken int32
L_0005: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
L_000a: stloc.0 
L_000b: ldloc.0 
L_000c: ret 

你可以看到它不是一种常量编写类型的代码:

const Type constType = typeof(int);

这将返回一个错误:

Constant initialize must be compile-time constant

2
+1非常好的回答他的问题,并证明它不是编译时常量。 - mtijn
RuntimeTypeHandle 是一个常量。 - leppie
RuntimeTypeHandle是一个结构体。不管怎样,这个改变是什么?RuntimeTypeHandle只是方法调用的参数。 - Felipe Pessoto

5

来自MSDN - 命名和可选参数:

默认值必须是以下类型之一的表达式:

  • 常量表达式;

  • 形如 new ValType() 的表达式,其中 ValType 是值类型,例如枚举或结构体;

  • 形如 default(ValType) 的表达式,其中 ValType 是值类型。


typeof 不一定返回编译时常量,因为它可能根据上下文返回不同的结果。


1
传递给 typeof 的类型必须在编译时解析。因此我无法理解你的意思。如果你所说的是真的,那么属性也应该禁止使用 'type constants'。 - leppie
Leppie,你说的“属性也应该禁止‘类型常量’”是什么意思?属性在哪里限制了值必须是常量? - Felipe Pessoto
1
@Fujiy - 传递给属性构造函数的参数需要是编译时常量。 - Oded
2
Oded,规则是:常量、typeof表达式或数组创建。 - Felipe Pessoto

4

因为它不一定是一个常量表达式。你的例子中涉及到了一个简单类的typeof,但如果这个类是泛型的呢?显然远非常量:

class MyClass<T>
{
  public void MyMethod(Type targetType = typeof(MyClass<T>))
  {
  }
} 

1
如果你习惯了C++中泛型类型的实现方式,即每个可能的类型T都会生成一个类的新实例,那么你可能仍然期望它是常量。但在C#和.NET中并非如此,因此在C#中,typeof(T)不能是编译时常量,但在基于模板的泛型语言中,它将是常量。 - Ed Avis

3

这个方法比较老,但如果有人正在寻找解决方法:

    class MyClass
    {
        public void MyMethod(Type targetType = null)
        {
            if(targetType == null)
            {
                targetType = typeof(MyClass);
            }
        }
    }


1

typeof(MyClass) 不是编译时常量吗?

这个特定的表达式是静态可解析的,但由于泛型的原因,typeof() 在执行时被评估,所以规则必须是 typeof() 调用不是编译时常量。

我想知道在 C# 1.0 中是否是这样,当时没有这样的争论...


1
我认为泛型不是唯一的原因。我认为这是因为这个代码可以运行:typeof(ClassInExternalAssembly)。直到加载实际的外部程序集之前它都无法被解析,因此它不是常量。 - Aidiakapi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接