Namespace question

F

Francois Malgreve

Hello everybody,

I have a pretty straightforward question regarding namespace.

Is there anyone who knows why the following code does not compile on the
line Type t = typeof(Name6.Name7.Name6.Class6) ? I am using Visual Studio
2006 by the way (.Net 2.0)

As far as I know "Name6.Name7.Name6" is a valid namespace but, somehow, some
operations on that namespace will not compile. From the example, we can
clearly see that it is because "Name6" is twice in the namespace.

namespace Name2
{
public class Class1
{
Type t = typeof(Name2.Class1);
}
}

namespace Name3
{
public class Class2
{
Type t = typeof(Name3.Class2);
}
}

namespace Name4.Name5
{
public class Class4
{
Type t = typeof(Name4.Name5.Class4);
}
}

namespace Name6.Name7.Name6
{
public class Class6
{
Type t = typeof(Name6.Name7.Name6.Class6); // Does not compile! Why?
}
}

namespace Name8.Name9.Name89
{
public class Class7
{
Type t = typeof(Name8.Name9.Name89.Class7);
}
}

Best regards,

Francois Malgreve
http://www.malgreve.net
 
R

Roberto Albano

Trying to make same thing from another namespace does compile:

namespace Name6.Name7.Name6
{
public class Class6
{
//Type t = typeof(Name6.Name7.Name6.Class6); // Does not
compile! Why?
}
}
namespace aaa
{
public class Class7
{
Type t = typeof(Name6.Name7.Name6.Class6); // Does not
compile! Why?
}
}

Seems a reference mistake.
bye
Roberto
 
R

Roberto Albano

Trying to make same thing from another namespace does compile:

namespace Name6.Name7.Name6
{
public class Class6
{
//Type t = typeof(Name6.Name7.Name6.Class6); // Does not
compile! Why?
}
}
namespace aaa
{
public class Class7
{
Type t = typeof(Name6.Name7.Name6.Class6); // Does not
compile! Why?
}
}

Seems a reference mistake.
bye
Roberto
 
M

Marc Gravell

The first Name6 in your typeof expression matches the outermost
(current) namespace, i.e. bracketed here: Name6.Name7.[Name6]

To get what you want, you need to tell it to start at the start and
work upwards:

Type t = typeof(global::Name6.Name7.Name6.Class6); // compiles now

Marc
 
M

Marc Gravell

In your "aaa" case, the compiler doesn't find a match with Name6 to
the current namespace, nor to any includes, so it looks for a Name6 in
the root and presto finds matches all the way up. It is this conflict
with the current namespace that is the problem, and hence why global::
(which forces it to go straight to the root) fixes it.

To be honest, I've never needed "global::SomeNamespace" in production
code except for code generators... most of the time the easier option
is to name your classes and namespaces such that conflicts don't
arise.

Marc
 
M

Marc Gravell

See also section 10.8 of ECMA 334 - but note that this isn't one of
the easiest sections to follow. But it roughly boils down to "it'll
walk backwards from the current namespace (inclusive) until it finds a
match, then work forwards from there". If it gets to the top (global)
and hasn't found a match, then it errors. If it finds a match for part
of your expression, but then can't resolve everything going forward,
then it errors. In this case, it is the second failure that is being
the pain.

For reference, another solution is to alias the outer namespace, i.e.

using SomeAlias = Name6; // at very top of file, so refers to outer
Name6
....
Type t = typeof(SomeAlias.Name7.Name6.Class6); // works fine
anywhere*

Marc

*=assuming you don't declare a type/alias called SomeAlias!
 
F

Francois Malgreve

The code is indeed generated....

So, if I understand well, when i do a typeof, it will look for the namespace
Name6.Name7.Name6 while walking backward from the current namespace.
As the current namespace is Name6.Name7.Name6, the first Name6 (from the
right) will match and it will look for something like
Name6.Name7.Name6.Name7.Name6. Is that right?

I think that now I understand the specifications but i just feel that this
walking backward then walking forward is an unecessary and overly complex
feature which bring problems like this for generated code (in my case, code
generated by Visual Studio itself in BizTalk projects). For me, class name
should just be declared alone (if part of the current namespace or imported
with "using" keyword) or then fully qualified... Nothing in the middle... So
that it makes the code clearer and more easy to read...

It seems a bit of an over-engineered and not a straightforward feature to
understand for the average programmer himself.
Do sometimes too smart people do not keep things simple enough?
Anyway I am not here to complain, just to say it is a bit strange in my
taste.

I would like to thank you very much for the explanations but can you
nevertheless point me to some reference explaining this? I did not find
anything on MSDN and when they talk about namespace, the only thing
specified is to not use reserved words and some other trivial stuff.

Thanks again,

Francois Malgreve
http://www.malgreve.net
 
M

Marc Gravell

I suspect (without basis) that the "look in the local hierarchy" is
broadly because when you are in a more-specialized namespace, you will
be dealing with the more-generalized things in the same area - i.e. if
you are working in MyApp.Database.SuperSpecific, it is likely that you
will be touching on concepts from MyApp.Database and MyApp.

The best reference I could find is unfortunately the spec itself.
Sorry.

Still, at least in 2.0 we got the "get out of jail" card that is
"global::" - before this you could get into all sorts of trouble if
you (or more irritatingly, an external dll you referenced) chose
unfortunately namespaces / names.

Marc
 
F

Francois Malgreve

Marc,

What you said makes sense indeed. Thanks for sharing your idea on the
subject.
I can see indeed things like
class MyApp.Database.Connection
class MyApp.Database.SQL.Connection
class MyApp.Database.Oracle.Connection

So if i am in the namespace MyApp.Database.Oracle, i can access to the class
MyApp.Database.Connection by typing only Database.Connection (instead of the
fully qualified name).

So I guess that for code generators, they should always use "global::" to
avoid trouble like this one...

Thanks again for your help,

Francois Malgreve
http://www.malgreve.net
 
M

Marc Gravell

So I guess that for code generators, they should always use
"global::" to avoid trouble like this one...

Personally I'd be a little bit pragmatic on the subject. Such things
are very much the exception, so if your code-generator is only for
internal use, I would add "global::" to things as-and-when it becomes
a genuine issue. IMO, having conflicting type-names and/or namespaces
(as ancestor/descendant in the same hierarchy) isn't really a great
idea... if you can somehow revise your naming strategy to avoid this,
it would make life a lot simpler.

Obviously conflicting names are reasonable and expected when the types
are [to abuse the term] cousins (as opposed to sibling / ancestor /
descendant) - i.e. System.Windows.Forms.Button and
System.Web.UI.WebControls.Button are cousins (second cousins once
removed?), but this poses no conflict issues.

Marc
 
F

Francois Malgreve

In this case it is the user who chose the namespace....
But indeed it is an exceptional case.

But it can happen in cases like the original case i posted such as:

MyCompany.Schema.CompanyA
MyCompany.Schema.CompanyB
MyCompany.Schema.MyCompany. /// this case will issue problem...

So there can be either a naming convention that would forbit cases such as:
MyCompany.Schema.MyCompany or then detect those cases and add "global::"

Anyway thanks again for your insight.

Francois Malgreve
http://www.malgreve.net



Marc Gravell said:
So I guess that for code generators, they should always use "global::" to
avoid trouble like this one...

Personally I'd be a little bit pragmatic on the subject. Such things are
very much the exception, so if your code-generator is only for internal
use, I would add "global::" to things as-and-when it becomes a genuine
issue. IMO, having conflicting type-names and/or namespaces (as
ancestor/descendant in the same hierarchy) isn't really a great idea... if
you can somehow revise your naming strategy to avoid this, it would make
life a lot simpler.

Obviously conflicting names are reasonable and expected when the types are
[to abuse the term] cousins (as opposed to sibling / ancestor /
descendant) - i.e. System.Windows.Forms.Button and
System.Web.UI.WebControls.Button are cousins (second cousins once
removed?), but this poses no conflict issues.

Marc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top