I have this really weird problem in my code (.Net Framework 3.5). So, in a normal VB.NET program, I would do something like this :
Dim MyList As New List(Of Integer)
MyList.Add(3)
MyList.Add(5)
MyList.Add(9)
MyList.Add(17)
And if I put a "break" rigth after
Dim MyList As New List(Of Integer)
and put the mouse over "MyList" while code is paused, I should get : Count=0. However, I have a sub where I create a list just that way and get (when I break after it) : "Count = Property evaluation failed".
It seems like if my list has not enough space to hold the data... Here's the complete code I use to try out everything (by the way, the code itself doesn't really make sense since it's a part of my project). With it I can create the "weird" behavior and anyone can test this. Here's the code (sorry the Code Block button isn't working) :
Structure lPossibilitiesOutputStruct
Dim Pinion As GearOutputStruct
Dim Gear As GearOutputStruct
Dim Forces As ForcesStruct
Dim CenterDistance As Double
Dim Pitch As Double
Dim lStagePossibilities As List(Of lPossibilitiesOutputStruct)
End Structure
Structure GearOutputStruct
Dim TeethNbr As Integer
Dim RPM As Double
Dim FaceWidth As Double
Dim OutsideDiameter As Double
Dim Addendum As Double
Dim WholeDepth As Double
Dim OperatingPitchDiameter As Double
Dim OverPinData As OverPinOutputStruct
Dim SpanData As SpanOutputStruct
Dim AllowableBendingPower As Double
Dim AllowablePittingPower As Double
End Structure
Structure OverPinOutputStruct
Dim PinDiameter As Double
Dim OverpinMeasurement As Double
End Structure
Structure SpanOutputStruct
Dim TeethNbr As Integer
Dim SpanMeasurement As Double
End Structure
Structure ForcesStruct
Dim GearSetAxialForce As Double
Dim GearSetRadialForce As Double
Dim GearSetTangentialForce As Double
End Structure
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim lStagePossibilities As New List(Of lPossibilitiesOutputStruct)
Dim MyList As New List(Of Integer)
MyList.Add(3)
MyList.Add(5)
MyList.Add(9)
MyList.Add(17)
lStagePossibilities = lGeneratePossibilities(Nothing, Nothing, 3, 1)
End Sub
Private Function lGeneratePossibilities(ByVal ActualStage As lPossibilitiesOutputStruct, ByVal CSL As List(Of Integer), ByVal MaxStage As Integer, ByVal CumulatedRatio As Double) As List(Of lPossibilitiesOutputStruct)
Return Nothing
End Function
All I did is create a new project with a form and created that code. There's nothing else in the project. I played with the "targeted CPU" and that's all...
If I run that program with compile option to use x86 CPU, and put a break on the "lStagePossibilities = ..." I get the "Count = Property evaluation failed" when i put my mouse over MyList. If I run it with the x64 CPU, then everything is working fine... ("Count = 4"). If I go back with the x86 CPU, I get back the error. Even worst, if I comment the line "Dim Pinion as GearOutputStruct" or the line "Dim Gear as GearOutputStruct" or the line "Dim Forces as ForcesStruct" in the lPossibilitiesOutPutStruct structure declaration, then everything works fine with x86 CPU...
Could it be related to a kind of maximum size of a list ???
Thank you !
Jean
I bet if you changed some of the Strucures into Classes the problem will go away. It is a well known bug in Visual Studio that when Structures get large and try to allocate a lot of local memory things go bad in the debugger. Some of the structures contain other structures and the memory adds up. I bet in x64 the size of the structs gets bigger, due to packing.
To quote some MSDN blogs
Just so others know too. This issue was because of a large struct in my code as well. I converted it to a class and I could read the values of variables hovering over the objects. It worked in some functions and classes, but the error message where the large struct was contained had the error "Cannot evaluate expression because a thread is stopped at a point where garbage collection is impossible, possibly because the code is optimized." and it went away upon making the change. Hope it helps and confirms the solution.
To clarify, what is too big. My Struct has (rather had) ...
55 public variables
A constructor with 6 parameters
Two public functions (one of those was small and one was large, about 200 lines of code)
I believe structs are intended to be used as small containers of straight forward, simple, cohesive data and functionality, and I would agree that this one got too far out of hand. It started out small, of course, and the needs ballooned. Now that it's in a class where the cohesive data and functionality is now contained there, I can sleep at night. =)
It took me all of 5 minutes to convert it to a class. Easy enough.
Related
I am new to .net and am doing my best to understand the Nuances (or Nuisance). I am trying to print text on a form. I did find many examples of the Graphics class, DrawString() etc. Unfortunately, I cannot get any of them to work. The stumbling block for me seems to be the error “NullReferenceException” and/or the warning “variable usage before it has been assigned”. One example found at "http://msdn.microsoft.com/en-US/library/76c5db29(v=vs.80).aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1". vs2005 displays the warning "Variable 'myE' is used before it has been assigned a value. A null referene excpetion could result at runtime and sure enough when I run a NullReferenceException is thrown at "e.Graphics.DrawString(drawString, drawFont, drawBrush, drawPoint)" How do I fix this?
Public Class Form1
Public Sub DrawStringPointF(ByVal e As PaintEventArgs)
Dim drawString As [String] = "Sample Text"
Dim drawFont As New Font("Arial", 16)
Dim drawBrush As New SolidBrush(Color.Black)
Dim drawPoint As New PointF(150.0F, 150.0F)
e.Graphics.DrawString(drawString, drawFont,drawBrush, drawPoint)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim myE As PaintEventArgs
DrawStringPointF(myE)
End Sub
End Class
You can't do that.
Instead, handle the Paint event and draw everything you need to.
To trigger a redraw, call Invalidate().
Your question is broader than your problem.
You're asking what a null reference exception is; this question has been answered many times elsewhere. A NRE (NullReferenceException) is referring to a variable that isn't defined at all
We can think about memory as being a vast, open parking lot. When you define a variable, using a statement like this,
Dim myObject as Integer
... you're claiming one or more of the parking spaces in the parking lot. However, all you've done is declare that this spot is yours, but not what goes in it. To give it a value, simply use the equals operator.
myObject = 100
Simple objects, known as primitives, like strings, numbers and characters, have an implied value when they're not defined. For example, integers are assumed to be zero if they have no value.
In your program, when you get a NRE, mouse over each argument in the function and the object that the function is being called from. If any of them claim to have a value of Nothing, there's your problem. You've reserved space for your object, but not yet given it a value.
As SLaks said, your specific problem is related to how you're calling the method, but without a strong understanding of what Nothing means, it may not correctly address the underlying question>
Finally, let's look at code that's specifically yours. You call
Dim myE as PaintEventArgs.
In this statement, you have reserved space in the memory- that is to say, claimed a parking space we talked about earlier. However, it does NOT have a value! It's empty. The program cannot function properly because you're telling it to perform an action on something that doesn't exist. To fix it, use the New operator. When making new objects, first reserve them in memory (Dim actually stands for "define in memory") and then give them a value with the New operator. You'd see something like this:
Dim myObj As Object
myObj = New Object()
You can also do it inline:
Dim myObj As Object = New Object()
When you try to do that with your PaintEventArgs, you'll see that that's quite impossible. PaintEventArgs requires information that's taken from a Windows Form control. That method you've written needs to handle an event. This post is too long as it is, so hopefully someone else can explain events and how they're related to methods. Basically, each control (textbox, image, or even the picture itself) raises an event every time it "paints" to the screen. You can "handle" that event; or do actions when it occurs, by doing this:
Public Sub OnPaint(sender as Object, e as PaintEventArgs) Handles myControl.OnPaint
You are declaring that whenever myControl raises an event for OnPaint, it will call this method, with arguments provided from the control.
You cannot simply substitute the required arguments from elsewhere. In order for it to work properly, the event arguments must be passed from the control that you wish to paint to.
I hope this helps. Please let me know if I've been unclear.
here is the situation:
I have defined a structure called "cell"
in this structure I have included textbox called "display"
my code is this:
Dim new_cell As New cell
new_cell.display.Multiline = True
there are no syntax or run-time "errors" but having put a breakpoint on the second line, when the program gets to it it stops running the sub and carries on as normal, can anybody explain what is the problem?
EDIT
cell definition:
Structure cell
Dim candidates As List(Of Integer)
Dim constraints As List(Of Integer)
Dim x As Integer
Dim y As Integer
Dim display As TextBox
End Structure
As suggested, the second line of your first code snippet will throw a NullReferenceException. If that code is in the Load event handler of a form then, on 64-bit systems, the exception will just be swallowed and the only notification will be in the Output window.
If you want a TextBox then you have to create a TextBox. Where that TextBox gets created depends on what you're trying to achieve. Regardless, that type should be a class rather than a structure. You should also think about using properties rather than public fields and you also ought to think about starting appropriate names with an upper-case letter.
When compiling some code (declarations shown below) I get the error message 'Compile Error: Ambiguous name detected. SixTables'. I have looked here and elsewhere but cannot find anything that matches my problem. What appear to be the most common causes of this error, declaring two variables with identical names or giving the same name to a function and the sub that it is called from, do not apply. And yes, I know I could just change the name to something the system was happy with, but (1) I wouldn't learn what I'm doing wrong, and (2) I chose that name for a reason - it fits its purpose exactly :-)
Option Explicit
Dim ArmOfService As Byte
Dim CharacterNumber As Long
Dim CurrentTerm As Byte
Dim DecorationRollMade As Byte
Dim DecorationRollNeeded As Byte
Dim DiceSize As Byte
Dim GenAssignment
Dim GenAssignmentSwitchInt As Byte
Dim GenAssignmentSwitchOff As Byte
Dim iLoopControl
Dim jLoopControl
Dim kLoopControl
Dim LineIncrement As Integer
Dim lLoopControl
Dim Merc(100)
Dim NoOfDice As Byte
Dim OfficerPromotion(63 To 78) As Byte
Dim PromotionRollMade As Byte
Dim PromotionRollNeeded As Byte
Dim Roll As Byte
Dim SkillColumn
Dim SixTables
Dim SpecAssignmentSwitchEnd As Byte
Dim SurvivalRollMade As Byte
Dim SurvivalRollNeeded As Byte
Dim TechLevel As Byte
Dim Temp As Integer
Dim Term As Byte
Dim TestCount
Dim UnitAssignment
Dim WhichTable
Dim Year As Byte
EDIT: I'm so embarrassed that I can hardly bring myself to explain what the problem was. I knew I hadn't duplicated a name, since I was only using it once - as a function! Thanks all for your help, I'm now going to go and hide my face in shame...
From MSDN :
More than one object in the same scope may have elements with the
same name.
Module-level identifiers and project-level identifiers (module names
and referenced project names) may be reused in a procedure, although
it makes programs harder to maintain and debug. However, if you want
to refer to both items in the same procedure, the item having wider
scope must be qualified. For example, if MyID is declared at the
module level of MyModule , and then a procedure-levelvariable is
declared with the same name in the module, references to the
module-level variable must be appropriately qualified:
Dim MyID As String
Sub MySub
MyModule.MyID = "This is module-level variable"
Dim MyID As String
MyID = "This is the procedure-level variable"
Debug.Print MyID
Debug.Print MyModule.MyID
End Sub
An identifier declared at module-level conflicts with a procedure name.
For example, this error occurs if the variable MyID is declared at
module level, and then a procedure is defined with the same name:
Public MyID
Sub MyID
. . .
End Sub
Having had this issue many times, and not fully understanding why, I think there is an important fact that I have tested, and someone can confirm. It may be obvious to professional programmers, but I place this here for those that seek these answers on discussions, who are usually not professional programmers.
A variable declared within a sub() is not "declared" (memory assigned) until that sub() is executed. And when the execution of that sub() is complete, the memory is released. Until now, I thought Public variables acted in similar way; available to any module that used it, --BUT only existing as long as the module where they were declared was still executing.
However, for any Public variable who's declaration line is in any module in the workbook, that variable is declared and available at the execution of any module within the workbook, even if the module where the Public declaration exists is never called or executed.
Therefore, if you have a Public variable declaration in one module, and then again in a separate module that you plan to run independent of the first, Excel still sees 2 declarations for the same variable, and thus it is ambiguous.
To prove it, you can create a blank module within a workbook project, and add absolutely nothing except two Public declaration lines,
Public VariableX as String
Public VariableY as Integer
and those variables will be declared and available throughout the project, for any sub() executed. This fact is also probably the reason for the tip about minimizing the use of public variables.
Again, this may have been kindergarten level information for professional programmers, but most on this are not pros, and have to learn these lessons the hard way, or through discussion boards like this. I hope this helps someone.
When initialising a list or a queue or a stack or anything similar, which method is preferred?
Dim q as Queue(Of Integer) = New Queue(Of Integer)
or
Dim q as New Queue(Of Integer)
Also, I've started to use New for string and integer variables - is this stupid? Is there any disadvantage to using New rather than just setting the variable to the default setting? E.g.
Dim Num1 As New Integer
Dim Str1 As New String("")
Dim Bool1 As New Boolean
Thank you!
If you'd ask programmers whether they like typing more or less when writing a program then the usual answer is "less!". If you ask them whether they like more or less bugs, the usual answer is "less!" Those are conflicting goals.
The As New syntax has been part of VB.NET for a very long time. It however does come with strings attached, you leave it entirely up to the runtime to figure out whether or not a new object should be created. That does tend to be a bug generator. Sometimes you really do want to create a new object, even though the variable is already assigned. It is also rather ambiguous, in this snippet for example:
For ix As Integer = 0 To 42
Dim q As New Queue(Of Integer)
'' etc...
Next
Question is: do you get one instance of the queue, created in the first pass of the loop or do you get 43 of them? What was actually intended by the programmer? It isn't very clear from the syntax.
There is a 3rd alternative that you overlooked and the one I prefer. Available since VB9 (aka VS2008) called "type inference". Where you don't specify the type of the variable but leave it up to the compiler to figure it out. This option needs to be turned on with Option Infer On, it is turned on by default. It combines the advantages of the abbreviated syntax that As New has and still lets you create the object explicitly in your code with the New statement:
Option Infer On
...
For ix As Integer = 0 To 42
Dim q = New Queue(Of Integer)
'' etc...
Next
Where q is inferred to be of type Queue by the compiler and it is crystal clear that the code generates 43 instances of the queue. The exact equivalent in the C# language is the var keyword.
I'm migrating some VB6 code to VB.net,
the code contains a structure that contains 1d arrays, 2d arrays, and few other variables.
The general outline of the Vb.net structure is as under
Public Structure Test
Dim a As Single
Dim b As Single
Dim c As Single
<VBFixedArray(2)> Dim arr1() As Single
<VBFixedArray(2, 2)> Dim mdarr1(,) As Single
<VBFixedArray(4)> Dim arr2() As Byte
<VBFixedArray(4)> Dim arr3() As Short
<VBFixedArray(3, 2)> Dim mdarr2(,) As Integer
Dim d As Integer
Dim e As Decimal
End Structure
The call to the dll is declared as under
Public Declare Sub getState Lib "val.dll" (ByRef state As Test)
Elsewhere on this site I realized that we have to "marshal" the structure to allow it to be compatible with the unmanaged code that is about to accept it.
However I still receiving runtime errors when running the code, I don't have any clue of how to use the System.Runtime.InteropServices.Marshal class.
What would be the correct way to pass this structure to the dll?
EDIT:
The original VB6 data type is
Public Type Test
a As Single
b As Single
c As Single
arr1(0 To 2) As Single
mdarr1(0 To 2, 0 To 2) As Single
arr2(0 To 4) As Byte
arr3(0 To 4) As Integer
mdarr2(0 To 3, 0 To 2) As Long
d As Long
e As Currency
End Type
Do you have the source code for getState in the val.dll? If it's written in C or C++, and you have the source code or even just the headers, you could use the P/Invoke Assistant to automatically generate your VB.Net code.
Alternatively... (and please do post the original VB6 structure!)
You might need to allocate the arrays before calling getState, e.g. state.arr1 = {0.0, 0.0} etc.
The Decimal variable e could cause you a problem. In VB6 this was probably a Currency variable, and Decimal is not an exact equivalent as far as I can remember. There will be a way to tell VB.Net to marshal it like a Currency. Perhaps adding an attribute like this...
Sample code:
Imports System.Runtime
Public Structure Test
''blah blah
<InteropServices.MarshalAs(InteropServices.UnmanagedType.Currency)> _
Dim e As Decimal
''blah blah