Extending VB.net Classes in C#.net - c#

I am currently exploring the possibility of combining both VB.net and C#.net into the same solution, with a view to stopping writing VB.net code and later down the line, refactoring what's been written into C#. My understanding of the .net framework suggests that I can extend a class of one language using a class of another language, but I simply cannot find a way to make it work.
As a mock-up, I've created a VB.Net console app that looks a lot like this:
Namespace CrossLanguage
Module Module1
Sub Main()
Console.WriteLine("This is a test")
Console.ReadLine()
Dim x As New Test
x.WriteMeAnAnimal()
End Sub
End Module
Public Class Test
Sub WriteMeAnAnimal()
Console.WriteLine("An animal")
Console.ReadLine()
End Sub
End Class
End Namespace
This works and there's no real issue with it. I can run up the app and at the first ReadLine, I can submit anything I like and 'An animal' appears. Now, all I've done next is create a new C# project, with one class file. I've added a project reference to point to the VB.net project (which is fine), but I simply cannot get the C# class to see that the VB class exists:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Test;
namespace CrossLanguage
{
public class Dog : Test
{
}
}
The IDE errors on the references to Test, with the whole "could not be found, are you missing..." shenanigans.
Am I missing something?

It sadly seems that this was some quirk of Visual Studio. Having reviewed your comments, I sat down today and opened the solution to try a couple of things and, well, it works without me changing anything.
Thanks for your help regardless.
Ashilta

Related

how to use namespace of external project?

Currently :
I have the following Using in my program.
using Mtx;
which allows me to use Mtx.* properties. It refers to a file in "Externals" folder.
Path is : Externals/Mtx.dll
Needed :
However, for debugging purposes, I'd like to now have the whole mtx solution in external and use it.
Path is : Externals/Mtx/(solution in there with all folders)
How can I do so, so instead of Using refers to the Mtx.dll, it now refers to the solution and build it has part of its own?
I think that you are misunderstanding some concepts and mixing things. Let me explain with your own explanation:
I have the following Using in my program.
using Mtx; which allows me to use Mtx.* properties. It refers to a
file in "Externals" folder.
Path is : Externals/Mtx.dll
The using keyword allows you to use the classes inside a namespace without typing the whole namespace everytime. It has nothing to do with dll classes, you can use all the public dlls insidea class just using the whole namespace + the class name only adding it as a project reference.
Needed :
However, for debugging purposes, I'd like to now have the whole mtx
solution in external and use it
For debugging purposes all you need are the pdb's of the dlls used and you will be able to debug any class considering you have its source code without changing anything else.

Early Binding of a C# COM library in VBA

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.

C# Namespace reserved words

I make the following query, is that I am taking a project which contains a class project with namespace Application.ProyectoA is that now I need to use from a windows project and gives me problems with the proper namespace System.Windows.Application, now try thereby instantiate
_viewModel.Item = global :: Application.ProyectoA.ProyectoManager.Get (200);
I've also tried changing the name of the alias and using external alias, but you can not.
but does not recognize "Application.ProyectoA" anyone has any solution for this, change the namespace cumbersome Original is half as this project is used in several places.
Greetings and thank you very much.

Silly Namespace Question

Ok, I have a c# project named BusinessLayer which produces an assembly called BusinessLayer and the namespace is BusinessLayer.
Inside of this project, I am using folders to store code. One folder is called FilterElements and it has folders called FilterKeyReversal, FilterRandom and FilterToday.
Let's take the example of the FilterRandom folder. It has a class called LessThan10DaysGreaterThan50A with a namespace of BusinessLayer.FilterElements.FilterRandom and a single public static method called RunFilter();
In the code behind page of the website that is consuming this method, I have the using statement, Using BusinessLayer. I also have another using statement, using BusinessLayer.FilterElements.
I would think that to expose the RunFilter() method of the LessThan10DaysGreaterThan50A class, I could use the following syntax: FilterRandom.LessThan10DaysGreaterThan50A.RunFilter(), however I get the following error: The name FilterRandom does not exist in the current context.
If I use the following syntax inline, the error goes away: BusinessLayer.FilterElements.FilterRandom.LessThan10DaysGreaterThan50A.RunFilter(), or if I use a using statement of: Using BusinessLayer.FilterElements.FilterRandom, the following syntax works: LessThan10DaysGreaterThan50A.RunFilter().
I would rather use FilterRandom.LessThan10DaysGreaterThan50A.RunFilter() as it seems to make code more readable. If I use an alias with the following syntax of using FilterRandom = BusinessLayer.FilterElements.FilterRandom, I can get what I want, but don't really like the idea of using an alias since it can lead to confusion down the line.
I thought that since my BusinessLayer namespace has nested namespaces, I'd be able to pick up the remaining namespace, but I can't seem to get it to work. Anybody know how to make this work without using an alias, or am I going to have to use the entire namespace name every time?
Thanks.
Nope, it doesn't. I know it's very irritating.
My first try at solving this issue (I had the same issue) was adding these usings:
using FilterRandom = BusinessLayer.FilterElements.FilterRandom;
The problem then becomes that you have to add one for every sub namespace you want to include, and that becomes a mess.
How I permanently solved this is by changing the namespaces in the project so that, in your example, FilterRandom would e.g. be in BusinessLayer.
The problem you are actually seeing is that you have too many namespaces. It isn't strange it happens. They are a great way of organizing your code and classes and it's not that hard to have it go out of hand. What I mean by changing the namespaces is that I merged many small namespaces into larger ones. This sometimes means renaming classes, but my opinion is that the class name on itself should be meaningful, without the namespace prefix.
This way, I permanently solved these issues in my project (60kloc) and it worked out great.

explicitly refer to a class without a namespace in C#

The code I'm working with has a class called Environment that is not in any namespace. Unfortunately if I am in a class that imports the System namespace, there is no way to refer to the custom class called Environment. I know this was an unfortunate choice and should be refactored, but is there any way I can explicitly refer to the conflicting class?
In C++ it seems the way to do this is by using ::, and in Java there is something called global:: How do I do it in C#?
C# also has a global (or unnamed) namespace - you can use global:: to access your class:
global::Environment
See more on MSDN. Also see the :: operator.
You can create an alias for it as well:
using myEnv = global::Environment;
using sysEnv = System.Environment;
Should be global::Environment just like in Java
The code I'm working with has a class called Environment that is not in any namespace
You should absolutely change that. Or if it’s not your code, file a bug report and defer usage until the bug is fixed. Not using a namespace – that’s an absolute no-go.
(Notwithstanding the well-working solution posted by #Oded.)

Categories