Explanation of the 'using Namespace' directive [duplicate] - c#

This question already has answers here:
Importing nested namespaces automatically in C#
(7 answers)
Closed 7 years ago.
Whenever, I start a new project in C#, I get the following:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
Why does using System; not allow you to use the sub namespaces with just the one line? I'm looking for an underlying reason as to why this isn't allowed. In the example given in the answer by HuorSwords:
namespace First {
class A { }
}
namespace First.Second {
class A { }
}
I would still get an error if I do:
using First;
using First.Second;
function void Test()
{
A variable;
}
I would still have to differeniate between the two. So then why am I forced to declare both namespaces instead of just the one? Aside from potential ambiguity, is there any other reason why we have to declare each namespace like this?

Think about this situation:
namespace First {
class A { }
}
namespace First.Second {
class A { }
}
If the behavior could be as you propose, then when you reference First namespace declaring a using First; sentence, and declares a variable of class A, how the compiler can deduce what of your two A classes should be used?
You can reference any type without using any using sentence, just putting the full namespace reference when you declare the variable.
var firstA = new First.A();
var secondA = new First.Second.A();
Then, when you try to import two or more namespaces that contains classes equally named, the compiler raises an error in order you can specify what class should be used.

Related

The type or namespace name 'Text' could not be found when using System directive is active in C# [duplicate]

This question already has answers here:
Why can't i use partly qualified namespaces during object initialization?
(4 answers)
Closed last month.
I'm working in VS 2019. I have a using directive using System; at the top of my file. Console.WriteLine() returns no warnings or errors however, it won't compile Text.StringBuilder… without explicitly declaring the System namespace, is this a known bug or am I understanding the using directive incorrectly?
using System;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine();
Text.StringBuilder builder = new Text.StringBuilder();
}
}
}
StringBuilder is part of the System.Text namespace. In your code you have not specified the System.Text namespace. You need to either have a using System.Text; or use System.Text.StringBuilder in the code. I would prefer to have the using System.Text; like
using System;
using System.Text;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine();
StringBuilder builder = new StringBuilder();
}
}
}

Using ValueTuple while compiling a class from text runtime

I'm trying to compile a class from text at runtime. My problem is that my class uses a valueTupe in a function (AllLines), and I receive an error "C:\xxxx.cs(19,28): error CS0570: 'BaseClass.AllLines' is not supported by the language" when using this code
CodeDomProvider objCodeCompiler = new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();
CompilerParameters objCompilerParameters = new CompilerParameters();
objCompilerParameters.ReferencedAssemblies.Add("mscorlib.dll");
objCompilerParameters.ReferencedAssemblies.Add("System.IO.dll");
objCompilerParameters.ReferencedAssemblies.Add("System.Linq.dll");
CompilerResults objCompileResults = objCodeCompiler.CompileAssemblyFromFile(objCompilerParameters, filename);
EDIT:
The Textfile looks as follows :
using System;
using System.Collections.Generic;
using System.Linq;
namespace MyNamespace
{
public abstract class BaseClass
{
public List<(int LineNumber, string Value)> AllLines
{
...
}
}
}
I'm using Microsoft.CodeDom.Providers.DotNetCompilerPlatform v2.0.0.0,
Microsoft (R) Visual C# Compiler version 1.0.0.50618
Unsure if that is the actual version of roslyn.
Firstly, you were correct that you were using Roslyn as you are using Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider from the NuGet package Microsoft.CodeDom.Providers.DotNetCompilerPlatform.
However, the issue you are facing is that your text file does not contain valid C#.
Your declaration of List<T> is invalid in enclosing the type parameters in parentheses
You are adding names(?) to the type parameter declaration (LineNumber, Value).
You're providing two type parameters when List<T> only accepts one. (Maybe you meant to use a Dictionary<TKey, TValue>)
There is no body to your property declaration
Try replacing your text file with:
using System;
using System.Collections.Generic;
using System.Linq;
namespace MyNamespace
{
public abstract class BaseClass
{
public Dictionary<int, string> AllLines
{
get; set;
}
}
}
Note, you don't actually need using System or using System.Linq for this example. Also note, you don't need to use Roslyn for this. The old fashioned CodeDOM can compile it (replace Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider with Microsoft.CSharp.CSharpCodeProvider).

Stacking namespaces can't be referenced just like any other element?

So here is a snippet I made where one namespace in inside another (B is inside A).
Usually when you use 'using SpaceA;' you can access all elements without typing SpaceA.
This is the case for class A, but I cannot see SpaceB without having to type SpaceA.SpaceB. Why is this?
Here is the code:
using System;
using SpaceA;
namespace SpaceA
{
class A
{
public A()
{
Console.WriteLine("A");
}
}
namespace SpaceB
{
public class B
{
public B()
{
Console.WriteLine("B");
}
}
}
}
namespace TestingCSharp
{
class Program
{
static void Main(string[] args)
{
//This does not work
SpaceB.B x = new SpaceB.B();
//This does work
SpaceA.SpaceB.B y = new SpaceA.SpaceB.B();
}
}
}
Usually when you use 'using SpaceA;' you can access all elements without typing SpaceA.
Only the direct types which are members of SpaceA. A namespace-or-type-name is never resolved using a namespace in a normal using directive and then another "subnamespace" in the name. Note that this has nothing to do with how the types are declared (in terms of having a nested namespace declaration or just namespace SpaceA.SpaceB) - another example would be:
using System;
...
Xml.Linq.XElement x = null; // Invalid
See section 3.8 of the C# 5 specification for the precise details of how names are resolved.
One slight difference to this is if you have a using alias directive for a namespace, at which point that can be used to look up other namespaces
using X = System.Xml;
...
X.Linq.XElement x = null; // Valid

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
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
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();
}
}

Using Statement with Generics: using ISet<> = System.Collections.Generic.ISet<>

Since I am using two different generic collection namespaces (System.Collections.Generic and Iesi.Collections.Generic), I have conflicts. In other parts of the project, I am using both the nunit and mstest framework, but qualify that when I call Assert I want to use the nunit version by
using Assert = NUnit.Framework.Assert;
Which works great, but I want to do the same thing with generic types. However, the following lines do not work
using ISet = System.Collections.Generic.ISet;
using ISet<> = System.Collections.Generic.ISet<>;
Does anyone know how to tell .net how to use the using statement with generics?
Unfortunately, the using directive does not do what you want. You can say:
using Frob = System.String;
and
using ListOfInts = System.Collections.Generic.List<System.Int32>;
but you cannot say
using Blob<T> = System.Collections.Generic.List<T>
or
using Blob = System.Collections.Generic.List
It's a shortcoming of the language that has never been rectified.
I think you're better off aliasing the namespaces themselves as opposed to the generic types (which I don't think is possible).
So for instance:
using S = System.Collections.Generic;
using I = Iesi.Collections.Generic;
Then for a BCL ISet<int>, for example:
S.ISet<int> integers = new S.HashSet<int>();
The only way you can alias a generic type is to specialize it as follows.
using IntSet = System.Collections.Generic.ISet<int>;
You can not alias an open generic type as you have done in your example:
using MySet = System.Collections.Generic.ISet<>;
Your alias name is the same as the class name itself, so you still have ambiguity, just as if you had a using for each namespace. Give the alias of the class a different name, i.e.:
using FirstNamespace;
using OtherObject = SecondNamespace.MyObject;
public class Foo
{
public void Bar()
{
MyObject first = new MyObject;//will be the MyObject from the first namespace
OtherObject second = new OtherObject;
}
}
In some cases you can go with inheritance:
public class MyList<T1, T2> : List<Tuple<IEnumerable<HashSet<T1>>, IComparable<T2>>> { }
public void Meth()
{
var x = new MyList<int, bool>();
}
You can alias a class doing :
using Test = NameSpace.MyClass;
Only if the class is NOT generic.

Categories

Resources