In the Java and Python world, you look at a source file and know where all the imports come from (i.e. you know in which file the imported classes are defined). For example:
In Java:
import javafoo.Bar;
public class MyClass {
private Bar myBar = new Bar();
}
You immediately see that the Bar-class is imported from javafoo. So, Bar is declared in /javafoo/Bar.java
In Python
import pythonbaz
from pythonfoo import Bar
my_bar = Bar()
my_other = pythonbaz.Other()
Here, it is clear that Bar comes from the pythonfoo package and Other is obviously from pythonbaz.
In C# (correct me if I'm wrong):
using foo
using baz
using anothernamespace
...
public class MyClass
{
private Bar myBar = new Bar();
}
Two questions:
1) How do I know where the Bar-class is declared? Does it come from the namespace foo, or bar, or anothernamespace? (edit: without using Visual Studio)
2) In Java, the package names correspond to directory names (or, it is a very strong convention). Thus, when you see which package a class comes from, you know its directory in the file system.
In C#, there does not seem to be such a convention for namespaces, or am I missing something? So, how do I know which directory and file to look in (without Visual Studio)? (after figuring out which namespace the class came from).
Edit clarification: I am aware that Python and/or Java allow wildcard imports, but the 'culture' in those languages frowns upon them (at least in Python, in Java I'm not sure). Also, in Java IDEs usually help you create minimal imports (as Mchl. commented below)
1) Well, you can do the same thing in Java too:
import java.util.*;
import java.io.*;
...
InputStream x = ...;
Does InputStream come from java.util or java.io? Of course, you can choose not to use that feature.
Now, in theory I realise this means when you're looking with a text editor, you can't tell where the types come from in C#... but in practice, I don't find that to be a problem. How often are you actually looking at code and can't use Visual Studio?
2) You can use the same convention in .NET too, of course - and I do, although I don't have empty directories going up the chain... so if I'm creating a project with a default namespace of X.Y, then X.Y.Foo would be in Foo.cs, and X.Y.Z.Bar would be in Z\Bar.cs
That's also what Visual Studio will do by default - if you create a subfolder, it will create new classes using a namespace based on the project default and the folder structure.
Of course, you can also declare types in any old file - but mostly people will follow the normal convention of declaring a type with a corresponding filename. Before generics made delegate declarations rarer, I used to have a Delegates.cs file containing all the delegate declarations for a particular namespace (rather than having a bunch of single-declaration files) but these days that's less of an issue.
1) You're right. There is no "direct" way to know where your class comes from at first glance, but, as you said, you can jump to it in the IDE. But declaring the class this way is just the shortest way to do it. If you wanted, and assuming your Bar class comes from the Foo one, you could declare it
private foo.Bar myBar = new foo.Bar();
This way it would help knowing where your classes come from at first look.
2)When you add a reference to your class, the Add reference windows gives you the informations you are looking for.
And if you want to know where they come from after you declared it, there is a window named "Solution Explorer" where you can find these informations, under the "References" tree node.
You can set it to be always visible (which it is by default)
For Java and Python this is indeed an issue with conventions - import the class you need, not the entire package using wildcards.
In C# you can't do a using directive for the specific class you want, since it only works for namespaces (as the following error reveals). It would seem that C# remained true to the C++ concept of namespaces, and merged it with the #include directive for one easy way of referencing external classes.
using System.Net.Sockets.Socket; // Gives the following error:
// A using namespace directive can only be applied to namespaces;
// 'System.Net.Sockets.Socket' is a type not a namespace
And about the double Bar deceleration, it's simple - if the compiler has no way of knowing it will give an error:
using Foo; // Has class Bar {}
using Goo; // Has class Bar {}
Bar b = new Bar(); // Gives the following error:
// 'Bar' is an ambiguous reference between 'Foo.Bar' and 'Goo.Bar'
How do I know where the Bar-class is
declared? Does it come from the
namespace foo, or bar, or
anothernamespace? Visual Studio allows
me to jump there, of course, but what
if I am just taking a quick look at a
source file in my editor?
Essentially, you don't - but IntelliSense is helping. You cannot actually be sure by just taking a quick glance at the code, but you can hover over the symbol with your cursor, for example. But this is also possible in Python:
from foobar import *
from bazbaz import *
a_bar = Bar()
Where does Bar come from now?
In C#, there does not seem to be such
a convention for namespaces, or am I
missing something? So, how do I know
which directory and file to look in?
(after figuring out which namespace
the class came from).
No, assemblies do not correspond to directory structures, which, IMHO, is a good thing. The solution explorer is offering a view of all the references added to your project. These references being assemblies, have a concrete representation as a PE file somewhere on your machine. You can easily look at the properties of a reference to see where the physical file is located.
Edit: In order not to contradict other answers in this thread and create confusion: What I mean by saying assembly names do not correspond to directory names is that it is not actually enforced.
In C#, there does not seem to be such a convention for namespaces, or am I missing something?
I don’t know about other projects but I’m pretty sure that in every .NET project I have worked on, we used this convention, i.e. namespaces always corresponded to folder names (except for the outermost namespace(s) which correspond to the assembly from which the namespace comes).
Usually, the tooltip when you mouse-over the type name reveals some extra information. Else you could always right-click the type name, and 'Go to definition'.
Related
Take a look at following solution:
MySolution.sln
MyApp.csproj
MyClassLib.csproj
MyClass.cs
MyClassLib project referenced by MyApp project and contains MyClass.
MyClass is used only in MyApp, so it can be moved there.
Is there a way to determine such cases with some tool? Maybe Roslyn or Resharper inspections?
In case of complex solution with long history and many projects this is required feature.
No, there is no such tool for this.
Why? Easy: What if, sometime in the future, you create a MyApp2 and that also needs MyClass? Then it would be better if MyClass is not in the MyApp assembly.
Now you, as the human developing this, might know that there will never (although never say never) be a MyApp2 but a tool cannot possibly know this.
I have limited experience with ReSharper, but from my experience, ReSharper can not automatically detect these cases where a file can be moved, but can visualize these hierarchies.
Going back to your earlier example, the hierarchy tool would show that your MyClass.cs file is only used by a file in MyApp.csproj. (It would not explicitly say this, but you would be able to tell based on the hierarchy.)
You can either use CodeLens in visual studio to check where is used
or either right click on the class (or shift+f12) to "Find all references" and check where is used. This gives you a quick overview, give that you know your project structure, of the need of moving a class to some other place.
or use
Code analysis tools or other code tools to check redundancy etc.
You cannot determine those automatically unless you fiddle with these tools, as it's an edge case when yourself know wheter a class should be placed in some place or not and no AI can replace that, unless you write your own custom code analysis tool that does that particular task.
Edit: Since author seems so much driven and determined into digging into this problem, I suggest you to take a shot into T4 code generation, DSL, CodeDOM to check if you can actually generate or analyze the code you want
Or, create Custom code analysis rulesets or check if the ones already present suits for you
#MindSwipe is right. However, if you really need to do this then here's a hack:
ensure your solution is under version control. this can help later.
select project MyClassLib and run a find and replace in all files of the current project: public class with internal class.
build your solution to get a bunch of errors
open the ErrorList pane and sort it by Description
You should see error messages such as:
The type or namespace name 'MyClass' could not be found (are you missing a using directive or an assembly reference?).
If you see exactly 1 message per class then it means that class can be moved from the library project to the project that yielded this error. Otherwise it means it is shared by at least 2 projects; in this case you have to make it public again (undo the change made by the global replace for this class).
The name of one of my classes was changed and I can't change it back. I have to mantain backwards compatibility and I don't want to write an wrapper with the old name.
Is there any easy way to give a class 2 names or to give it an alias?
Lifted from a comment by the OP:
Don't tell me to use the using directive since it must be done in the consumer side, and I don't want to change the projects that are using my library.
Arguably, your best option is to use a refactoring tool (like Resharper) to help you automate the conversion from the old name to the new name. However, if this is untenable to you for some reason, here are some alternatives:
If the types are in different assemblies you may be able to use a Type Forwarder. These allow you to redirect all references for a given type to an assembly ... but if IIRC, they can also redirect them to a new name as well.
Otherwise, within a single .cs source file you can apply a using statement:
using OldClassName = SomeNameSpace.NewClassName
This doesn't solve the problem globally, however, as it may become painful to change many .cs files to include this using statement.
Another alternative, may be to create a sub-class of the new type and name it the old name:
public class OldClassName : NewClassName
This gives you aliasing for the new class, but will require that you create duplicate public constructors and proxy static method calls to the renamed type. This is far from ideal ... and I generally don't recommend this.
Unfortunately, as the library author, the only way is X inherits Y, which has certain caveats.
It's possible but unlikely you could cheat with IL assembly.
High-level question here:
I have spent a lot of time today educating myself on basic high-level concepts such as APIs, static and dynamic libraries, DLLs and marshaling in C#. Gaining all of this knowledge led me to what seems like a pretty basic question, and probably demonstrates a hole in my understanding of these concepts:
What I know:
DLLs may contain classes which in turn contains various class-members such as methods and fields, several of which I might want to utilize in my program
In C# we use the keyword "using" at the top of the code, to define a namespace we
want to include in our program
What I do not get:
I was under the impression that the actual methods were defined in the DLLs. How does my program find the actual functions that are defined in the DLLs, when all i give them is a namespace? It seems more intuitive to me to have "using XYZ.dll" at top, rather than "using XYZ_namespace".
Thanks a lot for helping me fill in the gaps here.
EDIT: Modified post to be specific to C#.
EDIT 2: For other people that wonder how their C# application actually gets a hold of the types made available through "using namespaceX", this is a good resource (in addition to the helpful posts below): http://broadcast.oreilly.com/2010/07/understanding-c-namespaces-and.html.
Basically the type you would like to use resides in libraries and you have to set Visual Studio to reference these libraries in order to make it possible to "use" its namespace in your code.
DLLs contain many routines / methods we might want to use in our
programs
Partially correct. .Net DLLs contain Classes, and these classes contain Members (Fields, Constants, Methods, Properties, Events, Operators, Indexers).
.Net is strictly OOP, and it does not allow code "floating in limbo". Everything is defined inside classes.
Classes are organized in Namespaces just to keep a naming separation and organization. Think of namespaces as "folders" that contain one or more classes, and that might be defined in one or more assemblies (DLLs).
For example, Classes inside the System namespace are defined in 2 assemblies (DLLs): mscorlib.dll and System.dll.
At the same time, these 2 assemblies contain many different namespaces, so you can think the Assembly to Namespace relation as a Many-to-Many.
When you put a using directive at the beginning of a C# code file, you're telling the compiler "I want to use classes defined in this Namespace, no matter what assembly they come from". You will be able to use all classes defined in such namespace, inside all assemblies Referenced from within the current project.
In C#, DLLs (aka assemblies) contain classes (and other types). These types typically have long full names, like System.Collections.Generic.List<T>. These types can contain methods.
In your References area, you have references to assemblies (this is part of your .csproj file). In a .cs file, you don't need to include any using to reference this DLL, because it's already referenced in your .csproj file.
If you include a line like using System.Collections.Generic;, that tells the C# compiler to look for System.Collections.Generic.List<T> when you type List<T>. You don't need to do it that way, however: you can simply type System.Collections.Generic.List<T>.
I was under the impression that the actual methods were defined in the
DLLs. How does my program find the actual functions that are defined
in the DLLs, when all i give them is a namespace?
The process of finding the correct code occurs through static or dynamic binding and also assembly binding. When you compile the code static binding will tell you if you wrote bad code or forgot to add a reference:
ClassInADifferentAssembly.M(); //Generally this will static bind and
cause a compiler error if you forgot to include a reference to
DifferentAssembly
Unless you are dealing with dynamic or reflection then you have static binding. Assembly binding is a different process. The overall process is complex, but basically assemblies are discovered in the the GAC, current location or you can even handle an event yourself, AppDomain.AssemblyLoad.
So when you add a using statement then static binding can successfully find the correct code in the context. However, you can still receive a runtime error if later the assembly fails to bind at runtime.
DLL is short for dynamic link library. And can be a class library containing classes, methods etc that can all be put under different namespaces.
So first you have to add a reference to the DLL into your project. When that is done, you then use a keyword such as "using" to basically shorten the path to reach the methods/classes in that particular namespace.
Example namespaces
Namespace.Something.SomethingMore.Finally.Just.One.More
Namespace.Something.SomethingMore.Finally.Just.One.More2
To reach classes under those namespaces you can do either of the following
using Namespace.Something.SomethingMore.Finally.Just.One.More;
using Namespace.Something.SomethingMore.Finally.Just.One.More2;
// Now you can access classes under those namespaces without typing the whole namespace
// Like in the row below
Class.GetData();
If you did not have the usings, you would still be able to access those classes. But would then have to type
Namespace.Something.SomethingMore.Finally.Just.One.More.Class.GetData();
Namespace.Something.SomethingMore.Finally.Just.One.More2.AnotherClass.GetData();
DLLs have a collection of functions.
You can calls these functions by one of 2 ways:
link with the DLLs export library (a lib file) or do the link in runtime:
Call LoadLibrary()
Call GetProcAddress and provide the name of the function you want. You'll need to cast it to the actual type (function pointer).
Call the function via the new function pointer.
Pretty simple stuff, just read it on MSDN.
C++ namespaces are just a part of the function name.
You can view what functions are exported from a DLL by using a tool called Dependency Walker.
Although this is a long question the coding and testing part should be really easy to reproduce.
I have created two separate Class Libraries in C# and I think I am running into a name collision problem caused by existing registry keys from my previous projects and trials.
Here are my two classes:
using System;
using System.Runtime.InteropServices;
namespace Test
{
[InterfaceType(ComInterfaceType.InterfaceIsDual),
Guid("ED5D264B-1D80-4A5D-9C14-8297D90B7037")]
public interface ITest
{
// body
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("8B261B92-8EC5-4CDC-A551-67DEB42137FF")]
[ProgId("Test.TestClass")]
public class TestClass : ITest
{
// body
}
}
and
using System;
using System.Runtime.InteropServices;
using ADODB;
namespace Test
{
[InterfaceType(ComInterfaceType.InterfaceIsDual),
Guid("ED5D264B-1D80-4A5D-9C14-8297D90B7037")]
public interface IConnection
{
// body
}
[ClassInterface(ClassInterfaceType.None)]
[Guid("8B261B92-8EC5-4CDC-A551-67DEB42137FF")]
[ProgId("Test.Connection")]
public class Connection : IConnection
{
// body
}
}
I have Exposed .Net Components to COM like this:
In order to access the assemblies from Excel I have added the ADODB references to the assembly, ticked make assembly COM visible and register for com interop. Also, I've added references to each *.tlb file(2 files for two projects) so I can access them using an early binding and use VBA Intellisense.
I have followed the same procedure on another machine and I can use early binding using the Connection as class.
I am thinking there are some old registry keys I haven't deleted on my original machine which will not allow me to use Connection as the class name in VBE. I've manually scanned my registry and deleted everything I could think of related to my project.
I have also deleted the project entirely and used a 3rd party software to scan registry for missing dlls however that didn't help:/
Removed all previously registered GUIDs and applied new ones each time I created a new Project (just in case)
Created new projects using different namespaces and class names (using ADODB;) I haven't been able to use early binding yet like this Test.Connection therefore I am assuming I have a name collision problem. I am suspecting the name class Connection to be causing it although I am not 100% sure.
The Test.TestClass namespace in VBA:
I can declare and use instances of the TestClass type in two ways using early binding:
Dim x as Test.TestClass
Dim x as TestClass
Now going into VBE Object Explorer F2 the TestClass is properly displayed in comparison to other libraries and general idea of using COMs.
However, when I want to use the Test.Connection library I am unable to use early binding following the same pattern as TestClass because the generated *.tlb file automatically changes(renames) the ProgId's. So, instead I have to bind it like this
Dim x As Test.Test_Connection
Dim x As Test_Connection
and the Object Explorer displays the names using _ (underscores) and not . (dots), which is easy to explain why this happens - keep reading :)
As it stands I am sure it is not the VBE environment that changes the names to avoid collisions. It is the VS' *.tlb generator.
I went to the assembly folder and opened both *.tlb files in Notepad++. I can clearly see that the *.tlb for the Test.Connection library already includes the names with the _s unlike the Test.TestClass which has .s
I have tried to manually edit the *.tlb file but as its a mixed binary file it takes some effect but also causes Excel to stop responding in some weird ways so I have to avoid this method.
I think I have explained well what the problem is and where it comes from. Now my question is: Are there any attributes to use in C# code to tell the *.tlb generator not to override my ProdIds? Are there any alternative ways of manipulating *.tlb files? Is this issue a name collision and is it avoidable without changing the name of Connection class?
I'm sorry for such long question but I have been digging and digging for almost a week now and I still cant solve this.
Note: In VBA ( or VBE Object Explorer ) using IntelliSense ctrl+space it does not seem that either Connection or Recordset have been used. Since they are not already reserved in the VBE environment I recon it has to do with my library itself.
As a reference to why this issue has been raised here, please see VBA equivalent to C# using or VB.NET imports creating aliases
Thank you very much for your time!
Do avoid focusing on the ProgId. You are not actually using it, the dialogs that you made a screenshot of show the actual class names, not the ProgId.
Getting the class name renamed to "Test_Connection" is normal behavior for the type library exporter. It will do so whenever it detects a conflict with another interface or class name that has the same name. You are certainly increasing the likelihood of this happening by also having a dependency on ADODB, it also has a Connection class. A very trivial solution is to simply rename your own type.
Your code snippet cannot reproduce this problem. But of course it is incomplete, we can't see what you are really doing in the code. You'll bring in the dependency on ADODB if any of your public methods use a type from this type library. Also note that there are non-zero odds that this will happen by accident. You might have written a method that intended to use your own Connection type but the compiler resolved it to the ADODB type.
An essential tool to debug this is Oleview.exe, run it from the Visual Studio Command Prompt. First create the type library for your C# assembly with Tlbexp.exe. Then use File + View Typelib, you'll see the content of your type library expressed in the IDL syntax. You'll have little trouble recognizing the mapping of your C# types to the IDL declarations.
Pay attention to the importlib directives at the top of the file. They should look like this:
// TLib : // TLib : mscorlib.dll : {BED7F4EA-1A96-11D2-8F08-00A0C9A6186D}
importlib("mscorlib.tlb");
// TLib : OLE Automation : {00020430-0000-0000-C000-000000000046}
importlib("stdole2.tlb");
There should only be those two. The first one imports the .NET types, defining _Object. The second one imports standard COM types, like IDispatch. If you see additional ones here then you increase the odds of a name collision.
This IDL also gives you a way to solve the problem, in case it is unsolvable, you can edit it to name the types the way you want them. Save it to a .idl file. And compile it with midl.exe /tlb to generate a type library with your preferred names. Do note that this is not something you want to have to do often.
I read that way back programmers have to think of special names for their classes in order to do not conflict with another one when the file got loaded on users PC. That is what I do not understand, if the class was within e.g. DLL, how it could collide with other class on that PC?
Even without namespaces, if I import a DLL, I guess I would need to call the class from that DLL so I could not make the code impossible to complile.
I would really appreciate explanation here, thanks!
example:
System.Drawing.Point and System.Windows.Point
So if a program references both assemblies, without the namespaces, the compiler will get confused when you declare Point p; or Point p = new Point(1,1);, for example
Consider if there are no namespaces. Then you load a type MyClass from an assembly. Now if you load another type from another assembly and there is a MyClass in there. How do you load the second type? How to do tell the compiler which one you want when you say
MyClass o = new MyClass()
The answer - you have to name namespaces to uniquely identify the class, otherwise it's ambiguous. So you say why not limit the name space to the assembly. This is fine, however it appears that is such a great idea that the designers of the platform introduced a concept where anyone can create multiple namespaces within an assembly to allow people to partition their code better. Then we ask why not allow namespaces to go across assemblies so that we can partition the code more easily.
You have many uses for namespaces and it's upto you the app designer to come up with something that works for you - even if its only one namespace.
DLL Hell, the Inside Story is a good summary of the old issues - C# addressed this issuer per design - so you do not need to worry anymore.