Marco
Marco

Reputation: 2473

Visual Studio unable to resolve class name unless using nested using block

I have a class that's name is the same as the namespace is is contained within:

Class File ReadModel.cs

namespace App.Core.ReadModel
{
    public class ReadModel 
    {
    } 
} 

Class File MyClass.cs

using App.Core.ReadModel; // this does not work

namespace Something
{
    // using App.Core.ReadModel (Works if I un-comment)

    public class MyClass
    {            
       public void test()
        {
            var x = new ReadModel(); 
        }
    }
}

When trying to instantiate the class, even when trying to add a using directive at the top, the compiler is still unable to resolve the class. HOWEVER, if I put the using statements nested within the namespace, it works fine.

Can someone pls explain why this works? This is a new feature I've just discovered.

The error is: App.Core.ReadModel is a namespace but is used like a type

Upvotes: 1

Views: 1229

Answers (2)

Nicholas Carey
Nicholas Carey

Reputation: 74345

The difference between

using System  ;
using Foo.Bar ;

namespace My.Widget.Tools
{
  public class MySpecialTool
  {
    ...
  }
}

and

using System ;

namespace My.Widget.Tools
{
  using Foo.Bar ;

  public class MySpecialTool
  {
    ...
  }
}

is that in the first case, the directive using Foo.Bar ; causes the objects in the namespace Foo.Bar to be imported into the unnamed (global) namespace for the compilation unit. In the second case, the using directive imports the objects in the namespace Foo.Bar into the namespace My.Widget.Tools.

The difference has to do with search order in resolving unqualified references.

Unqualified references are resolved by first searching within the enclosing named namespace. If the reference is not resolved, then the unnamed (global) namespace for the compilation unit is searched.

Consider the case where the above namespace Foo.Bar contains a visible class that conflicts with a class contained in the System namespace.

In the first case, where the Foo.Bar namespace has been loading into the global namespace, you'll get an error regarding an ambiguous reference if you try to reference the conflicting object: it will search the enclosing namespace first, on not finding it, it will then look into the global namespace and find multiple objects and whine.

In the second case, the enclosing namespace is searched first, on finding an object of the desired name, the unqualified reference is resolved and the compiler is happy: no conflict.

Note that you can coerce the search order to the global namespace by qualifying an object reference with the global:: prefix. You can also define your own aliases with the using directive, either for a namespace:

using io = System.IO ;

or for a type:

using IntList = System.Collections.Generic.List<int> ;

the caveat with defining an alias for the namespace is that you then have to use the alias to resolve a reference. An alias defined for a type just gives you a [perhaps] shorthand way of naming the type. Probably more useful for generics than anything else. I don't see a lot of value in doing something like:

using Row = System.Data.DataRow ;

outside of writing obfuscated C#.

See also this question: Should 'using' statements be inside or outside the namespace?

§16 of ISO/IEC 23270:2006 (Information technology -- Programming languages -- C#) will tell you far more than you ever wanted to know about namespaces and using directives.

See also this MSDN piece on namespace aliases: http://msdn.microsoft.com/en-us/library/c3ay4x3d(v=vs.80).aspx

Upvotes: 3

cwharris
cwharris

Reputation: 18125

Edit again:

Nicholas answered your revised question very nicely. Please see his answer:

Visual Studio unable to resolve class name unless using nested using block

EDIT:

Using have to be at the top of the file. Move the using above the first namespace.

Example:

namespace App.Core.ReadModel
{
    public class ReadModel
    {
    }
}

using App.Core.ReadModel; // cannot be placed here. Must be at top of file.

namespace App
{
    public class Program
    {
        public static Main()
        {
            var obj = new ReadModel();
        }
    }
}

Original Answer (irrelevant to question):

Option 1: Rename Namespace

namespace App.Core.IO
{
    public class ReadModel
    {
    }
}

Option 2: Use an Alias

using MyReadModel = App.Core.ReadModel.ReadModel;

public class Program
{
    public static void Main()
    {
        var obj = new MyReadModel();
    }
}

Option 3: Qualify Type Name

public class Program
{
    public static void Main()
    {
        var obj = new App.Core.ReadModel.ReadModel();
    }
}

Upvotes: 3

Related Questions