Since updating to Visual Studio 2017 I have observed unwanted behavior when constructing if statements, in that intellisense doesn't recognize variable names when I attempt to surround the clause in parenthesis. Consider the following incomplete code:
class AnythingClass
....
end class
public Sub doSomething()
Dim anythingInstance as new AnythingClass
if anyt
When typing code in this manner, the instance "anythingInstance" will be suggested by autocomplete. However, if I open parentasis when starting the if clause as below
class AnythingClass
....
end class
public Sub doSomething()
Dim anythingInstance as new AnythingClass
if (anyt
then the declared variable will not show in the autocomplete suggestions. The class name AnythingClass will show up in the suggestions, but not the instance
UPDATE
(edit) THIS ANALYSIS IS INCORRECT, please see my answer for details as to why
I have tried creating a brand new project and get the expected behavior. So this only appears to happen in projects that have previously been upgraded from older versions of visual studio.
I have attached a couple of screenshots for the skeptics!
Based on comments from #Maciej Los and #TnTinMn, I have managed to piece together the issue.
If you write the code as:
IF (an...
with a whitespace between the IF and the arguments, Then autocomplete appears to treat it as an If statement and will display instance variables. However if you write the code as
IF(an...
with no whitespace, autocomplete appears to treat it as the If operator and not show declared instances. Quite why this is the case, I don't know. My original analysis of there being a difference between new projects and previously imported ones was incorrect.
Related
Base Reference: Ten Code Conversions for VBA, Visual Basic .NET, and C#
Note: I have already created and imported a *.dll, this question is about aliases.
Let's say the programmatic name of a Test class is TestNameSpace.Test
[ProgId("TestNamespace.Test")]
public class Test ...
Now, say a C# solution has been sealed and compiled into a *.dll and I'm referencing it in a Excel's VBE. Note: at this point I cannot modify the programmatic name as if the *.dll wasn't written by me.
This is in VBA : Instead of declaring a variable like this:
Dim myTest As TestNameSpace.Test
Set myTest = new TestNameSpace.Test
I'd prefer to call it (still in VBE)
Dim myTest As Test
Set myText = new Test
In C# you would normally say
using newNameForTest = TestNamespace.Test;
newNameForTest myTest = new NewNameForTest;
Note: Assume there are no namespace conflicts in the VBA project
Question: is there an equivalent call in VBA to C# using or VB.NET imports aliases?
Interesting question (constantly using them but never thought about their exact meaning). The definition of the Imports statement (same for using) is pretty clear: its only function is shortening the references by removing the corresponding namespaces. Thus, the first question to ask is: has VBA such a thing (namespaces) at all? And the answer is no, as you can read from multiple sources; examples: Link 1 Link 2
In summary, after not having found a single reference to any VBA statement doing something similar to Imports/using and having confirmed that VBA does not consider the "structure" justifying their use (namespaces), I think that I am in a position to say: no, there is not such a thing in VBA.
Additionally you should bear in mind that it wouldn't have any real applicability. For example: when converting a VB.NET code where Imports might be used, like:
Imports Microsoft.Office.Interop.Word
...
Dim wdApp As Application
the code would be changed completely, such that the resulting string will not be so long:
Dim wdApp As Word.Application ' Prefacing the library's display name.
I think that this is a good graphical reason explaining why VBA does not need to have this kind of things: VB.NET accounts for a wide variety of realities which have to be properly classified (namespaces); VBA accounts for a much smaller number of situations and thus can afford to not perform a so systematic, long-named classification.
-------------------------- CLARIFICATION
Imports/using is a mere name shortening, that is, instead of writing whatever.whatever2.whatever3 every time you use an object of the given namespace in a Module/ Class, you add an Imports/using statement at the start which, basically, means: "for all the members of the namespace X, just forget about all the heading bla, bla".
I am not saying that you cannot emulate this kind of behaviour; just highlighting that having an in-built functionality to short names makes sense in VB.NET, where the names can become really long, but not so much in VBA.
The answer is no: there is a built-in VBE feature that recognizes the references added to a project and creates aliases at run-time(VBE's runtime) if there are no name collisions
In case of name conflicts in your registry all . dots will be replaces with _ underscores.
» ProgId's (Programmatic Identifiers)
In COM, it is only used in late-binding. It's how you make a call to create a new object
Dim myObj = CreateObject("TestNamespace.Test")
» EarlyBinding and LateBinding
In early binding you specify the type of object you are creating by using the new keyword. The name of you object should pop up with the VBA's intellisense. It has nothing to do with the ProgId. To retrieve the actual namespace used for your object type - open Object Explorer F2 and locate it there
This article explain where the names come from in Early Binding Section
use the same link for When to use late binding
for MSDN Programmatic Identifiers section please see this
Using SSRS 2008 R2 with embedded code, the VB.Net code compiler seems to err whenever I need to do anything beyond the simplest of statements.
For instance, I want to use the LINQ Select function to perform some operations on the elements of a collection, but BIDS keeps throwing compiler errors on lines of perfectly valid VB.Net code.
Public Function SplitToIDs(ByVal multiValue As String) As Integer()
Dim regex As New System.Text.RegularExpressions.Regex("((?>.*?);#\d*;#)", System.Text.RegularExpressions.RegexOptions.Compiled Or System.Text.RegularExpressions.RegexOptions.ExplicitCapture Or System.Text.RegularExpressions.RegexOptions.CultureInvariant Or System.Text.RegularExpressions.RegexOptions.IgnoreCase)
Dim results As New System.Collections.Generic.List(Of String)()
Dim matches As System.Text.RegularExpressions.MatchCollection = regex.Matches(multiValue)
For Each mvMatch As System.Text.RegularExpressions.Match In matches
results.Add(mvMatch.Value)
Next
'Dim pairs As String() = SplitToPairs(multiValue)
'Dim names As System.Collections.Generic.IEnumerable(Of Integer) = System.Linq.Enumerable.Select(pairs, Function(p) Integer.Parse(Microsoft.VisualBasic.Split(p, ";#")(1)))
Dim names As System.Collections.Generic.IEnumerable(Of Integer) = System.Linq.Enumerable.Select(results, Function(p) Integer.Parse(Microsoft.VisualBasic.Split(p, ";#")(1)))
Return System.Linq.Enumerable.ToArray(names)
End Function
On the line 42, which is the comment immediately above where I call System.Linq.Enumerable.Select, Visual Studio 2008 (the VS Shell installed by SQL Server 2008 R2), gives this error when I attempt to preview my report:
An error occurred during local report processing.
The definition of the report '/XXXX' is invalid.
There is an error on line 42 of custom code: [BC30201] Expression expected.
I have already learned that [BC30201] is a generic error with little relation to a missing expression. As seen in my code, I have fully namespace qualified every function or variable beyond the most basic System namespace classes. In the Report Properties dialog, References tab, I've already referenced both mscorlib and System.Core to make sure all the functions I'm using in my code can be resolved to a System assembly.
So a few questions...
Can Anonymous Functions be called and used in SSRS 2008 R2 Reports' embedded code?
In getting to this point, I was getting the same [BC30201] error when I attempted to call one method in the embedded code from another. Yet, I was sure I had some simpler methods in an earlier iteration of this report (or another report) were this actually worked... Should we be able to call one custom method from another within the embedded code?
Notes:
I'm highly tempted to create a separate code module, but I really don't want to fight the political battle necessary to convince lots of people that we should install custom assemblies on our Reporting servers. But unless, I can call those assemblies directly from various report expressions, I may still need to use the embedded code to make the assemblies' methods available to the report.
The source data comes from a SharePoint 2010 list. Many of the columns are Lookup columns that allow multiple values. The method above strips out the delimiters and values to return a collection of IDs.
I created an extension method in VB.NET in Visual Studio 2013 but it will not show up in Intellisense.
Imports System.Security.Claims
Imports System.Runtime.CompilerServices
Imports Connect.Common.Portable
Namespace Authorization
Public Module ClaimsPrincipalExtensions
<Extension()>
Public Function CurrentFirmNumber(ByVal principal As ClaimsPrincipal) As Integer
Dim c As Claim = principal.FindFirst(AuthorizationClaimTypes.LOGGED_IN_FIRM_NUMBER)
If (c IsNot Nothing) Then
Dim firmNumber As Integer = 0
If (Integer.TryParse(c.Value, firmNumber)) Then
Return firmNumber
End If
End If
Return 0
End Function
End Module
End Namespace
I have tried everything I could find on StackOverflow and other sites to solve this to no avail, including everything mentioned here.
In my calling code I include the right namespace, and the compiler and runtime are perfectly happy if I call this extension. That is, the code runs fine and correctly calls the extension method. It is simply intellisense that doesn't show it to me.
However, if I try to reference the method directly using the full namespace, as opposed to from the extended object, it shows up in intellisense.
Any ideas?
UPDATE:
So, it gets weirder. I had a colleague open up the same source and he gets intellisense.
As well, original extensions that used to work for me now have the same intellisense problem. However, if I start typing out the extension name intellisense does see it once it becomes a unique name.
For example, If I type "CurrentPrincipal.Current.C" Intellisense suggests "Claims", but not "CurrentFirmNumber", as that is part of the type. However, if I add a "u" it then suggests "CurrentFirmNumber", which is my extension.
I have some VB.NET (which I don't normally deal with) code which must be converted to C# (which I normally do).
The code happens to be in a Windows Forms app. I notice a couple of places such as:
Public Sub New()
ParentWindow = Me
where there is no ParentWindow variable defined, and it doesn't seem to be inherited here:
Public Class MainWindow
Inherits System.Windows.Forms.Form
Private Shared parentWindow As MainWindow
'....
(Though note that there is a similar variable with a lower-case first letter.)
and this:
DocumentCount = 0;
where, again, there is no corresponding variable definition and a straight conversion to C# Windows Forms indicates that there is no such member in the parent class.
Am I missing an import somewhere, or is this a feature peculiar to VB.NET that doesn't translate directly to C#?
If this is working it's likely that you have Option Explicit set to off. This is a feature of VB.Net that allows for variables to be used before they are declared. Try adding the following to the top of the file
Option Explicit On
VB is case insensitive, so it's actually assigning to parentWindow and documentCount.
(Edited in response to other comment)
VB is case insensitive. So parentWindow and ParentWindow may very well refer to the same variable. Usually the IDE fixes the case for you though...
This question already has answers here:
Why can I access an item in KeyCollection/ValueCollection by index even if it doesn't implement IList(Of Key)?
(2 answers)
Closed 6 years ago.
I have a VB.NET project where I am able to iterate through the keys and values collections of a dictionary object using an index:
MyDictionary.Keys(idx)
MyDictionary.Values(idx)
When this code is taken from the test project and placed into the real project I get the following error:
'System.Collections.Generic.Dictionary(Of Double, String).KeyCollection' cannot be indexed because it has no default property.
and
'System.Collections.Generic.Dictionary(Of Double, String).ValueCollection' cannot be indexed because it has no default property.
This is using VB.NET and VS 2008. I don't know what the difference would be from one project to the next that would cause this error. The test is a console application and the program is a winforms app.
What conditions would cause the default property of these collections to change?
Edit - Thank you for all of the answers that tell me how to loop through a dictionary. Those, answers, however, do not answer my question of why I can use an index in one project and not the other. Should I not be able to copy and paste the code from one .net project to another and have it work the same? And, no, option strict, is not the cause of the problem.
Edit - Attempt to reproduce what I'm seeing:
Create a new VB.NET Console Application using VS 2008
Copy and paste the following code into the module:
Imports System.Collections
Imports System.Collections.Generic
Module Module1
Public dtf As Dictionary(Of Double, String)
Public Sub BuildDictionary()
dtf = New Dictionary(Of Double, String)
dtf.Add(1.0, "1")
dtf.Add(0.0, "0")
End Sub
Public Sub Search()
For idx As Integer = 0 To dtf.Keys.Count - 1
If dtf.Keys(idx) = 0 Then
Exit Sub
End If
Next
End Sub
Sub Main()
End Sub
End Module
In the line in sub search that says "dtf.Keys(idx) = 0" place your cursor after the right parenthesis and backspace you should get a tooltip that says, "<Extension> ElementAtOrDefault(index as Integer) as Double - index: the zero based element of the index to retrieve.
I am not getting that in my other project. Even though it seem I have the same references and settings.
KeyCollection does not implement indexers like that, you must enumerate through the MyDictionary.Keys.
c#
foreach(double key in MyDictionary.Keys)
Console.Write( MyDictionary[ key ] )
vb
For Each key As Double in MyDictionary.Keys
Console.Write( MyDictionary( key )
Next key
Looping with a for(;i++;) wouldn't be the correct way of going through your hashtable (dictionary) since it is not an array it really has no concept of an array index (array[index])
I bet your real project had OPTION STRICT ON, as all projects should, and that your test project had it OFF. That's why you didn't get a compiler error in your test project.
EDIT: the poster says he has OPTION STRICT ON for both projects. That makes this more interesting.
I still think the most likely reason for this difference is that in one case, the compiler compiled the code and saw the error; but in the other case, the compiler didn't comile the code. Is this the same version of Visual Studio on the same machine at the same time? Same .NET Framework version in both cases?
Are these both the same type of project, for instance, are they both console applications? I ask because ASP.NET Web Site "projects" usually don't attempt to compile code until the code is called. If your test project were such a "project", and if you didn't actualy test the code (that is, if you didn't actually step into this code and see it work), then you might have assumed that the fact you could press F5 meant that all the code was compiled, when it wasn't.
My next thoughts would be to see if MyDictionary was really of the same type in both cases.
Beyond that, if you really need to know why this happened, I'd make a copy of the "real" project, and start changing it to be more and more like the test project. This would probably be a matter of mass deletions at first. I'd keep changing it either until the problem was found, or until the two were identical.
EDIT 2: The default console project imports the System.Linq namespace (see the "References" tab in project properties). This import brings the ElementAtOrDefault extension method into scope. This extension method extends IEnumerable(Of T); in your case IEnumerable(Of Double), which is what the Keys property implements.
What surprises me about this is that VB.NET is automatically applying this extension method. In C#, the method would need to be explicitly named.
If you remove the Import of System.Linq, you'll find that your test application gets the same error as the production application.
The Keys and Values property of Dictionary(Of TKey,TValue) do not have an indexer property. They are implementations of ICollection vs. IList and hence don't support accesses by Index. If you want to iterate through a Dictionary, the best way is a For Each loop.
For Each pair in MyDictionary
Dim key = pair.Key
Dim value = pair.Value
Next
EDIT
Have you checked to make sure that System.Core is referenced in both projects and that you have a project level imports for System.Linq? That's the only thing I can think of that would produce a difference in ElementAtOrDefault which is a method inside of system.Core.
I'm still a bit baffled why that method would be bound to for a simple indexer. Going to look into that