How to add a using directive outside a namespace using Roslyn? - c#

I have a CSharpSyntaxRewriter that adds a new using directive to my file:-
public class AddUsingDirective : CSharpSyntaxRewriter
{
public override SyntaxNode VisitNamespaceDeclaration(NamespaceDeclarationSyntax node)
{
// this adds the using directive inside the namespace not outside
node = node.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("MyCompany.MyProject.DataAccessLayer.Abstractions"))).NormalizeWhitespace();
return base.VisitNamespaceDeclaration(node);
}
}
The problem is that is adds the new using directive inside the namespace but I want to add it to the other existing namespaces above the namespace declaration. Any ideas how I can do this?

public override SyntaxNode VisitCompilationUnit(CompilationUnitSyntax node)
{
// this adds the using directive inside the namespace not outside
node = node.AddUsings(SyntaxFactory.UsingDirective(SyntaxFactory.ParseName("MyCompany.MyProject.DataAccessLayer.Abstractions"))).NormalizeWhitespace();
return base.VisitNamespaceDeclaration(node);
}

Related

Namespace not found

I have defined the following code for my interface:
using Android.Widget;
using Android.Graphics;
using Xamarin.Forms;
using Android.Content.Res;
using MyApp.Droid;
[assembly: Dependency(typeof(MeasureString))]
namespace MyApp.UWP
{
public class MeasureString : IMeasureString
{
public double calculateWidth(string text)
{
Rect bounds = new Rect();
TextView textView = new TextView(Forms.Context);
textView.Paint.GetTextBounds(text, 0, text.Length, bounds);
var length = bounds.Width();
return length / Resources.System.DisplayMetrics.ScaledDensity;
}
}
}
This is my interface class:
using System.Threading.Tasks;
namespace MyApp
{
public interface IMeasureString
{
public double calculateWidth(string text);
}
}
I'm getting the error "Type or Namespace MeasureString not found". Possible missing using directive or assembly reference".
I thought I'd copied everything over from my template interface which works fine and contains just the same namings.
How would I go on investigation what I'm missing?
Your attribute is applied outside the namespace block, so that class isn't actually in scope.
You can either add a using statement for your own namespace or fully qualify the classname.

Why can't i use partly qualified namespaces during object initialization?

I suspect this is a question which has been asked many times before but i haven't found one.
I normally use fully qualified namespaces if i don't use that type often in the file or i add using namaspacename at the top of the file to be able to write new ClassName().
But what if only a part of the full namespace was added ? Why can't the compiler find the type and throws an error?
Consider following class in a nested namespace:
namespace ns_1
{
namespace ns_1_1
{
public class Foo { }
}
}
So if i now want to initialize an instance of this class, it works in following ways:
using ns_1.ns_1_1;
public class Program
{
public Program()
{
// works, fully qualified namespace:
var foo = new ns_1.ns_1_1.Foo();
// works, because of using ns_1.ns_1_1:
foo = new Foo();
}
}
But following doesn't work:
using ns_1;
public class Program
{
public Program()
{
// doesn't work even if using ns_1 was added
var no_foo = new ns_1_1.Foo();
}
}
it throws the compiler error:
The type or namespace name 'ns_1_1' could not be found (are you
missing a using directive or an assembly reference?)
I assume because ns_1_1 is treated like a class which contains another class Foo instead of a namespace, is this correct?
I haven't found the language specification, where is this documented? Why is the compiler not smart enough to check if there's a class or namespace(-part)?
Here's another - less abstract - example of what i mean:
using System.Data;
public class Program
{
public Program()
{
using (var con = new SqlClient.SqlConnection("...")) // doesn't work
{
//...
}
}
}
Edit: now i know why this seems very strange to me. It works without a problem in VB.NET:
Imports System.Data
Public Class Program
Public Sub New()
Using con = New SqlClient.SqlConnection("...") ' no problem
End Using
End Sub
End Class
This obvious way unfortunately not working but you can make all this by an alias namespace:
using ns_1_1 = ns_1.ns_1_1;
public class Program
{
public Program()
{
var no_foo = new ns_1_1.Foo();
}
}
The documentation says:
Create a using directive to use the types in a namespace without having to specify the namespace. A using directive does not give you access to any namespaces that are nested in the namespace you specify.
So the using only includes the types (not the namespaces) that are defined in the specified namespace. In order to access types of nested namespace you need to specify it explicitly with a using directive as you did in your first example.
This is documented in the standard in 3.8 Namespace and Type Names, but it's a bit convoluted to follow.
The gist of it that a partial namespace reference is only looked for in the namespace where it occurs, and each layer outwards. using-directives are not checked.
In your example, ns_1_1.Foo would be found if Foo is found anywhere in:
Program.Program.ns_1_1.Foo
Program.ns_1_1.Foo
ns_1_1.Foo
Partial namespaces will work only if your current class is part of that partial namespace. Using statements are not considered for accessing types through partial namespace.
For instance this will work because your current namespace is ns_1
namespace ns_1
{
public class Program
{
public Program()
{
var no_foo = new ns_1_1.Foo();
}
}
}

Missing directive of assembly reference

I added an existing form (and its references) to another project and I am trying to show the new form. There are no coding issues, just a reference error:
The type or namespace 'frmEmail' could not be found (are you missing a
using directive or an assembly reference?)
I cannot figure out what "using" or reference I failed to use when importing the other form. Any ideas?
Here is the code causing the error:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Notify_Setup
{
public partial class frmNotifications : Form
{
public frmNotifications()
{
InitializeComponent();
pbBlue.MouseEnter += new EventHandler(pbBlue_MouseEnter);
}
private void pbGreen_Click(object sender, EventArgs e)
{
frmEmail frmEmail = new frmEmail();
frmEmail.Show();
this.Hide();
}
}
}
You need to pull the namespace in. For example, if this was how your form currently was in the other project:
namespace Your.Form.Namespace { // this is important
public class YourForm : Form {
// stuff
}
}
Then in the project you're adding it to.. you need to add your assembly as a reference, then import the namespace in like this:
using Your.Form.Namespace; // import the namespace
namespace Other.Project {
public class OtherClass {
YourForm _form; // this is fine now
}
}
The other options is to fully qualify the type. What this means, is to use the entire namespace and type name in the declaration. It would be like this:
namespace Other.Project {
public class OtherClass {
Your.Form.Namespace.YourForm _form; // this is fine too
}
}
I added an existing form (and it's references) to another project and I am trying to show the new form.
It looks like the form you added was frmNotifications, but is creating an instance of frmEmail. Did you also added it?

c# using directive depth

I'm trying to understand the c# using directive...Why does this work...
using System;
using System.ComponentModel.DataAnnotations;
namespace BusinessRuleDemo
{
class MyBusinessClass
{
[Required]
public string SomeRequiredProperty { get; set; }
}
}
but this does not?
using System;
using System.ComponentModel;
namespace BusinessRuleDemo
{
class MyBusinessClass
{
[DataAnnotations.Required]
public string SomeRequiredProperty { get; set; }
}
}
The second results in a compile error "The type or namespace DataAnnotations cannot be found. Are you missing are missing a using directive or an assembly reference?
using directive makes it possible to use class names from the namespace you specified as its argument. Since DataAnnotations is not a class, but a namespace, it's not accessible in second case. You should either use fully qulified class names NS1.NS2.Class1, or start you program with using NS1.NS2; and then use Class1.
Because you can either use Fully Qualified Class Names or just use the ClassName and let .NET resolve it via using directive. There is no middle ground.
Class1 -
NameSpace1.NameSpace2.NameSpace3.Class1
can be accessed as
using NameSpace1.NameSpace2.NameSpace3;
...
... Class1.DoSomething();
...
or
...
NameSpace1.NameSpace2.NameSpace3.Class1.DoSomething();
...
but not like
using NameSpace1.NameSpace2;
...
NameSpace3.Class1.DoSomething();
...
In last case what compiler would actually be looking for is root namespace NameSpace3 which clearly does not exist. It won't try to look for System.NameSpace3 or NameSpace1.NameSpace3 or NameSpace1.NameSpace2.NameSpace3 etc etc.

Namespace collisions

How is it possible that .NET is finding the wrong 'MyType' in this scenario?
I have a type A.B.C.D.MyType in a project that I'm working on, and I'm referencing a DLL that has a type A.B.MyType? I do not have any 'using A.B;' statements anywhere in my code, and I do have 'using A.B.C.D;'. When I compile, the compiler thinks any naked reference to 'MyType' means 'A.B.MyType'.
I know I could just rename the class or use an alias, but I'm wondering how this is even possible.
Any ideas?
Thanks!
Are you working in a namespace that is under A.B namespace? (for example A.B.X) if so the C# namespace resolutions (ECMA-334 C# Language Specification : 10.8 10.8 Namespace and type names) says:
... for each namespace N, starting
with the namespace in which the
namespace-or-typename occurs,
continuing with each enclosing
namespace (if any), and ending with
the global namespace, the following
steps are evaluated until an entity is
located...
and then followed by:
If K is zero and the namespace
declaration contains an
extern-alias-directive or
using-aliasdirective that associates
the name I with an imported namespace
or type, then the
namespace-or-type-name refers to that
namespace or type
This means that name resolution starts at the current namespace and searches all namespaces up to the root, and only after this hierarchical search ends, then the namespaces imported with the using clause are searched.
The following example prints "Ns1.Foo"
using Ns1.Foo.Foo2;
namespace Ns1.Foo
{
class Foo
{
public void Print()
{
System.Console.WriteLine("Ns1.Foo");
}
}
}
namespace Ns1.Foo.Foo2
{
class Foo
{
public void Print()
{
System.Console.WriteLine("Ns1.Foo.Foo2");
}
}
}
namespace Ns1.Foo.Bar
{
class Bar
{
public void Print()
{
new Foo().Print();
}
static void Main()
{
new Bar().Print();
}
}
}
Edit: Adding a using clause inside a namespace, will make so that the namespace is searched before the hierarchical search of current namespace is done is done. Change the example to:
namespace Ns1.Foo.Bar
{
using Ns1.Foo.Foo2;
class Bar
{
public void Print()
{
new Foo().Print();
}
static void Main()
{
new Bar().Print();
}
}
}
and Ns1.Foo.Foo2 will be printed.
Edit: changed example
Is your code in namespace A.B or A.B.C? If so, that's probably the issue. Use a using directive like this:
using TheTypeIWant = A.B.C.D.MyType;
then just refer to TheTypeIWant in your code.
EDIT: I've just tried the "using MyType=A.B.C.D.MyType" option, but that doesn't work. The above is fine though.
Just a guess: in your project properties, is the "default namespace" set to A.B ?

Categories