0

I have two distinct namespaces, each with a Thing class:

namespace First.Second.Third
{
    public class Thing { }
}

namespace Fourth.Fifth.Sixth
{
    public class Thing { }
}

Now I try to use Thing elsewhere, and of course the compiler complains due to the ambiguous reference to that class:

namespace ConsoleApp1
{
    using First.Second.Third;
    using Fourth.Fifth.Sixth;

    internal static class MainEntryPoint
    {
        internal static void Main(string[] args)
        {
            var x = new Thing(); // Complaint.
        }
    }
}

If I add an alias to one of the namespaces in the using directive, the compiler error goes away:

using MyAlias = First.Second.Third;
using Fourth.Fifth.Sixth;

Now the compiler thinks I'm referring to Fourth.Fifth.Sixth.Thing when I do var x = new Thing();.

Why does the compiler resolve the ambiguity simply by adding an alias to one of the namespaces? Why does it automatically pick the namespace that I did not alias?

I expected this to be well documented and covered many times before on SO and elsewhere, but I can't find the answer. Can someone help me find the dupe if there is one?

EDIT: I'm not on the same page as everyone I guess. Here's a real-world example that might help:

If I have two people named "Bob", and I just say "here, give this to Bob", you won't know whom to give it to. If I say, well one is "Bob Smith" and the other is "Bob Johnson", of course I can now say "here, give this to Bob Smith." Now, if I say, "let's call Bob Smith by a new name: Bob Brady". If I then say "here, give this to "Bob", that is still ambiguous. See my point?

11
  • Because compiler does not know which one of Thing do you want to use? Commented Jun 13, 2017 at 13:54
  • To reference First.Second.Third you must explicitly instantiate it as x.Thing, so there's no ambiguity thanks to the alias (you aren't using the namespace directly). Commented Jun 13, 2017 at 13:55
  • 1
    You need x.Thing to get a thing from First.Second.Third and Thing without x refers to Fourth.Fifth.Sixth.Thing . They each have a unique name so no ambiguity. Commented Jun 13, 2017 at 13:57
  • 1
    You wanted to create it as Thing the compiler didn't know which one you meant. The alias fixed that. If you did new First.Second.Third.Thing it would have never complained in the first place. It stops being ambiguous because you "promised" the compiler that you will always refer to First.Second.Third.Thing as MyAlias.Thing Commented Jun 13, 2017 at 13:59
  • 1
    @rory.ap Your real world example isn't quite the same thing, though. A more apt way of describing it would be "if I don't give you someone's last name, assume that it's 'Johnson' and if I use the last name 'Brady' I really mean 'Smith', now give me 'Bob'". Since you didn't specify the last name, the compiler assumes that it's 'Johnson' and gives you 'Bob Johnson', no ambiguity. If you didn't use the alias it'd be like saying "assume that if I don't give a last name it's either 'Johnson' or 'Smith'". Commented Jun 13, 2017 at 14:25

4 Answers 4

10

I think your misconception is that you believe that aliasing automatically imports the types of a namespace.

using Fourth.Fifth.Sixth;

makes all types in this namespace visible without additional qualification.

using MyAlias = First.Second.Third;

does nothing besides giving the namespace a new name, without importing it. So, if you change using First.Second.Third; into using MyAlias = First.Second.Third; the ambiguity is removed because Thing from First.Second.Third is no longer visible without further qualification. But obviously the other using is still importing Thing from Fourth.Fifth.Sixth.

Also see the corresponding definitions in the C# 5.0 Language Specification:

A using-alias-directive (§9.4.1) introduces an alias for a namespace or type.

A using-namespace-directive (§9.4.2) imports the type members of a namespace.

Sign up to request clarification or add additional context in comments.

13 Comments

Hmmm...now we're on to something. Can you point to where this documented? I'd just like to read the rules. I'm reading through the C# spec but can't find it.
I've read that already. It doesn't get to your point about importing vs. not importing. Why does giving the namespace a nickname (alias) remove ambiguity between two identically-named types they both have?
@rory.ap they are not identically named w.r.t. fully qualified names. That's why there's no ambiguity.
"A using-alias-directive introduces an identifier that serves as an alias for a namespace or type within the immediately enclosing compilation unit or namespace body." - So all that has been done is give a shorter name of MyAlias to First.Second.Third without importing it - so there is effectively only one using statement "Fourth.Fifth.Sixth", so no ambiguity. You can add "using First.Second.Third;" back into your code & the compiler will not tell you it is has already been used - but your ambiguity will be back.
|
2

Here's the thing, you do:

using First.Second.Third;
using Fourth.Fifth.Sixth;

Now everything in First.Second.Third and Fourth.Fifth.Sixth can be referenced without their fully qualified name. This includes Thing however since both contain Thing then doing new Thing() is ambiguous.

If you do:

using First.Second.Third;
using MySixth = Fourth.Fifth.Sixth;

Then only First.Second.Third can be referenced without their fully qualified name, the namespace Fourth.Fifth.Sixth is just also known as MySixth, therefore no ambiguity.

Note the wording in: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive

For the first case it does say:

using System.Text;

To allow the use of types in a namespace so that you do not have to qualify the use of a type in that namespace

For the alias it does not mention qualifying of namespace use:

using Project = PC.MyCompany.Project;

To create an alias for a namespace or a type

Comments

0

I believe you're confusing the x alias with the x variable. Since you use x for alias in First.Second.Third if you want to use the Thing from that then you should use

var aThing = new x.Thing();

HTH, Mike

2 Comments

See my update. I changed the alias name, didn't fix anything. Same question.
see @mjwills answer. If you use Thing() without the alias name then it assumes you mean the one that's not aliased.
0

By putting an alias on the first option, you have effectively resolved the ambiguity (there aren't two Thing now - there is a Thing and a MyAlias.Thing).

If you refer to Thing it will default to using the non-aliased version (unless you specifically use the alias). This is exactly the same way that Console.ReadLine works if you use using System.

See below.

namespace Test
{
    using MyAlias = First.Second.Third;
    using Fourth.Fifth.Sixth;

    public class Program
    {
        static void Main()
        {
            var x = new Thing(); // non aliased
            var y = new MyAlias.Thing(); // aliased
            Console.ReadLine();
        }

    }
}

See also:

12 Comments

I know it's defaulting. I stated that in my question. Why? Can you point me to some documentation?
Well it defaults to the non-aliased one for the same reason why if you have use System; then you can use Console.ReadLine() (i.e. you don't need to write System.Console.ReadLine())
I just tried this in one of my programs and the act of adding the alias made it show red wherever that item was used. Creating the alias not only allows you to use the alias name, it requires it. Essentially First.Second.Third is not visible to the compiler.
First.Second.Third is visible to the compiler - you just need to use the MyAlias alias that is specified in my (and your) code sample. If I specify an alias, it is mandatory to include the alias. That is the whole point of using an alias.
The point I am making is that your question is effectively the wrong way around. You are asking 'why does it choose the non-aliased one'. The point I am making is that how every other using statement (System, System.Linq etc) works - why would you expect this to be different?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.