Consider this:
[SomeAttr(typeof(Bar))]
class Foo {
class Bar {
}
}
...and this:
class Foo : ISomething<Bar> {
class Bar {
}
}
The first example compiles, the second doesn't. To use a nested type reference when inheriting from a generic type I must qualify it with the parent's type name:
class Foo : ISomething<Foo.Bar> {
class Bar {
}
}
My question is, why? and why doesn't this restriction apply when referring from an attribute in the parent type (first example)?
It's all about the scope of the declaration. Consider the following code:
namespace FooSpace
{
class Foo : ISomething<Bar>
{
class Bar { }
}
}
The line of code class Foo : ISomething<Bar>
is in the FooSpace
namespace, but not inside the class Foo
. At this point, Bar
has no meaning. Bar
by itself would only have a meaning within the scope of the Foo
class itself.
To use the class Bar
in any code outside the Foo class, you have to qualify it as Foo.Bar
. This rule also applies within the class declaration itself.
Why is it this way? Couldn't the complier automatically work out that you must mean the nested Bar
within the same class?
Well, for one thing there could potentially be other nested classes called Bar
within other classes in the same namespace, as follows:
namespace FooSpace
{
class Foo : List<Foo.Bar>
{
public class Bar { }
}
class Foo2 : List<Foo2.Bar>
{
public class Bar { }
}
}
Without the qualifier, which Bar
do you mean? The compiler would have no way to tell. So it's much more consistent for the compiler not to try and guess, but to insist on an explictly qualified class name.
As for the attribute case, although a class-targetting attribute is declared above the class declaration like this:
[SomeAttr(typeof(Bar))]
class Foo { ...
in reality, the compiler translates this to something more like this:
class public auto ansi beforefieldinit FooSpace.Foo extends [mscorlib]System.Object
{
.custom instance void FooSpace.SomeAttr::.ctor ... etc.
In other words, the actual SomeAttr
attribute object is created inside the class, using the parameter you supply. This parameter typeof(Bar)
is of course then valid, as it exists within the class scope of Foo
.
The related question here discusses this case too.
It's interesting to note that exactly the same rules and behaviours apply to class attributes which access const or static class members - you don't need the specify the class name, because the attribute is actually created inside the class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With