Why doesn't C# allow a typeof as a default parameter?
Asked Answered
B

5

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

Isn't typeof(MyClass) a compile-time constant?

Bouchier answered 20/1, 2012 at 9:48 Comment(0)
O
5

From MSDN - Named and Optional Parameters:

A default value must be one of the following types of expressions:

  • a constant expression;

  • an expression of the form new ValType(), where ValType is a value type, such as an enum or a struct;

  • an expression of the form default(ValType), where ValType is a value type.


typeof does not necessarily return a compile time constant as it may return different results depending on context.

Ora answered 20/1, 2012 at 9:49 Comment(4)
The type passed to typeof must be resolved at compile time. Hence I cannot see what you mean. If what you say is true, attributes should also disallow 'type constants'.Flaviaflavian
leppie, what you mean by "attributes should also disallow 'type constants'"? Where does attributes restrict values to be constants?Dashboard
@Fujiy - Parameters passed in to attribute constructors need to be compile time constants.Ora
Oded, the rule is: A Constant or typeof expression or a array creationDashboard
D
11

I am not a IL expert, but seems that it calls a method at L_0005:

return typeof(int);

It´s the same of:

.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 

You can see that it isn´t a constant writing type of code:

const Type constType = typeof(int);

That returns a error:

Constant initialize must be compile-time constant
Dashboard answered 20/1, 2012 at 9:57 Comment(3)
+1 nice way of answering his question and proving it isn't a compile time constantGunpaper
The RuntimeTypeHandle is a constant, however.Flaviaflavian
RuntimeTypeHandle is a struct. Anyway, what is this change? RuntimeTypeHandle is just the argument of method callDashboard
O
5

From MSDN - Named and Optional Parameters:

A default value must be one of the following types of expressions:

  • a constant expression;

  • an expression of the form new ValType(), where ValType is a value type, such as an enum or a struct;

  • an expression of the form default(ValType), where ValType is a value type.


typeof does not necessarily return a compile time constant as it may return different results depending on context.

Ora answered 20/1, 2012 at 9:49 Comment(4)
The type passed to typeof must be resolved at compile time. Hence I cannot see what you mean. If what you say is true, attributes should also disallow 'type constants'.Flaviaflavian
leppie, what you mean by "attributes should also disallow 'type constants'"? Where does attributes restrict values to be constants?Dashboard
@Fujiy - Parameters passed in to attribute constructors need to be compile time constants.Ora
Oded, the rule is: A Constant or typeof expression or a array creationDashboard
G
4

because it isn't necessarily a constant expression. your example features a typeof on a simple class but what if the class was generic? obviously this isn't constant by far:

class MyClass<T>
{
  public void MyMethod(Type targetType = typeof(MyClass<T>))
  {
  }
} 
Gunpaper answered 20/1, 2012 at 9:55 Comment(1)
You might still expect it to be constant if you're used to generic types being done the way they are in C++, where each possible type T generates a new instance of the class. That's not how it works in C# and .NET, so in C# typeof(T) can't be a compile-time constant, but in a template-based generic language it would be.Bunkmate
F
3

This is old but if someone is looking for a Workaround:

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

Fosse answered 14/6, 2019 at 19:21 Comment(0)
O
1

Isn't typeof(MyClass) a compile-time constant?

That particular expression is statically resolvable, yes, but typeof() is evaluated at execution time (because of generics), so the rule must be that a typeof() call isn't a compile-time constant.

I do wonder whether it was in C# 1.0, when there was no such argument to be made...

Oech answered 20/1, 2012 at 10:22 Comment(1)
I don't think generics is the only reason for this. I think it's because this works: typeof(ClassInExternalAssembly). It cannot be resolved until the actual external assembly is loaded, and therefore, it's not constant.Prepositor

© 2022 - 2024 — McMap. All rights reserved.