I have a stack overflow error, and I'm fairly sure I don't have any kind of infinite recursion (at least I've stared at the error for a few hours now and I can't imagine how its looping infinitely).
Here is the code:
public decimal? Amount
{
get
{
if (!string.IsNullOrEmpty(_savedWork.Amount))
return decimal.Parse(_savedWork.Amount);
else
return null;
}
set
{
if (value.HasValue)
{
_savedWork.Amount = value.Value.ToString();
Percent = null;
}
else
_savedWork.Amount = "";
OnPropertyChanged("Amount");
}
}
#Note I have a string housed in a nullable decimal, that's why I'm converting it. Please don't make me go into why I'm doing this.
the line savedWork.Amount = value.Value.ToString() is where I get the error.
Basically I'm thinking that my stack is just too small (or my code is too big I suppose). I basically run this code twice, and it works when in one form, but not when I make another form and place it in there, so I think the difference between these 2 forms is tipping the stack.
Is there a way to identify what I'm doing wrong? I want to find out what part of the code is taking up a too much or is persisting too long etc.
I've done some research about how the stack/heap work and I know about PerfMon.exe, but as far as I know it only works for the heap. Is there a similar tool that I can use for the stacks my program is running?
I found this post about 2 tools called windbg and cdb but I can't find much about how to install/use them. Are these tools the right way to go?
Alternatively if there is an infinite loop or something that would be great.
Edit
here is the code requested for the Amount Property (its autogenerated by EntityFramework) as I said in the comments, the step into doesn't even reach here. I really do think my stack limit is just being reached.
public global::System.String Amount
{
get
{
return _Amount;
}
set
{
OnAmountChanging(value);
ReportPropertyChanging("Amount");
_Amount = StructuralObject.SetValidValue(value, true);
ReportPropertyChanged("Amount");
OnAmountChanged();
}
}
Final Edit
Ok so Meta-Knight's answer showed me that I did indeed have an infinite loop. I had an event handler subscribed to the PropertyChanged event of the DisplayTypeOfInvestment (the class that the Amount Property belongs to). The handler looked like this:
void DisplayTypeOfInvestmentList_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
_typeOfInvestmentFormSavedWork.TypeOfInvestment.Clear();
foreach (DisplayInvestmentFund d in _displayInvestmentFundList)
{
_typeOfInvestmentFormSavedWork.TypeOfInvestment.Add(d.SavedWork);
}
OnPropertyChanged("TypeOfInvestmentFormSavedWork");
}
The TypeOfInvestmentFormSavedWork is a completely different class that contains in it it's own version of the SavedWork class that we see that is used an the Amount property. The point of this method was to update this TypeOfInvestmentFormSavedWork property to the new value of _savedWork when the Amount property changes. For some reason this is triggering the DisplayTypeOfInvestment viewmodel's PropertyChanged. I didnt figure it out but I changed the method to look like this:
void DisplayTypeOfInvestmentList_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "Amount" || e.PropertyName == "Percent")
{
_savedWork.TypeOfInvestment.Clear();
foreach (DisplayInvestmentFund d in _displayInvestmentFundList)
{
_savedWork.TypeOfInvestment.Add(d.SavedWork);
}
OnPropertyChanged("CurrentWork");
}
}
The if statement stops the weird properties being changed in the DisplayInvestmentFund when the Add method is called.
I realise this answer doesnt make much sense, but for me to explain this in full detail would take a very long time. I also realise that this probably means my code is bad. I'm not sure what to do about that. Thanks for the help guys.
My guess is that you're assigning to Amount in one of the event handlers that OnPropertyChanged calls.
Another possibility is that you have code in the setter of SavedWork.Amount that calls YourClass.Amount again.
But why don't you just debug it? Just step through the code in the Visual Studio debugger.
The stack trace should also be useful. With endless recursion you typically get a repeating sequence of methods. If my guess is correct the repeated part will be something like:
MyClass.set_Amount
MyClass.OnPropertyChanged
OtherClass.myClass_amount_changed
Is the class of which Amount member of the same type as _savedWork?
Because there could be this loop:
1) You assign a value to Amount
2) Before the value is set, you assign a value to _savedWork.Amount
3) Before the value of _savedWork.Amount is set, the line is triggered again
4) Before the value of _savedWork._savedWork.Amount is set...
5) Before the value of _savedWork._savedWork._savedWork.Amount is set...
And this goes to infinity and beyond.
There must be a recursive call to the Amount setter somehow. You could debug it by "stepping into" the properties instead of stepping over. If you set VS so that it doesn't step into properties, you can still put a breakpoint inside your setters to simulate a "step into". As for VS not stepping into .edmx files, as CodeInChaos mentioned, maybe the class is tagged with a DebuggerStepThrough attribute.
Is _savedWork an object of the same type as the Amount property you listed? Because that will give you a stack overflow error! In that case, you need to find a way to talk about Amount without invoking the getter and setter.
Related
I am working on a project, where I have to invoke a method when a value gets below a certain threshold. This event then writes some information to the user.
I have decided to put it in the setter, as it should be displayed when the user tries to get information.
The problem is that I still want to get something afterwards (as it is a getter), but I get stackoverflow and I can see that the getter is called many times. I thought this was weird, since the .invoke should only invoke the event and then move on. So how can i move further from the invoke, instead of having it go back to the beginning of the setter every time it is called,
This is the current setter:
get
{
if (_balance <= BalanceThreshold)
UserBalanceNotification.Invoke(this,BalanceThreshold);
return _balance;
}
And this is the general event:
public delegate void UserBalanceNotification(User user, int balanceThreshold);
As this is a more general question I doubt more code snippet would support it
I've written a C# Windows form created in Visual Studio 2017.
In a button click event handler, I have a simple if statement that never completes:
if (listViewAddedKeys.CheckedItems.Count < added.Count)
listViewAddedKeys is a ListView, and "added" is a Hashtable.
This is the complete function:
private void buttonSaveAdded_Click(object sender, System.EventArgs e)
{
try
{
saveFileDialog.ShowDialog();
if (saveFileDialog.FileName != String.Empty)
{
OnProgressEvent("Saving Data...");
DisableControls(this.Controls);
if (listViewAddedKeys.CheckedItems.Count < added.Count)
HashFromSelected(ref listViewAddedKeys, ref added, out currentSaving, false);
else
currentSaving = added;
BeginSaveData.BeginInvoke(saveFileDialog.FileName, ref currentSaving,
OnSaveDataCallback, BeginSaveData);
}
}
catch (Exception ex)
{
OnProgressEvent("Problem in buttonSaveAdded_Click(): " + ex.Message);
}
}
listViewAddedKeys is a ListView, and "added" is a Hashtable.
If I break on the line:
DisableControls(this.Controls);
and add "listViewAddedKeys.CheckedItems.Count" to the "Watch 1" tab of the debugger, the debugger is unable to retrieve the value (Function evaluation timed out). If I change that to just "listViewAddedKeys" I'm able to drill down into it quite a bit (for instance, I can see that the item count is 1,478,670), however, if I continue to scroll down through it, Visual Studio crashes.
I'm not doing anything tricky with threads, and the only lock I have on anything has a breakpoint set on it which hasn't yet triggered.
I tried following the advice here, but none of the output in windbg matches with the items they want me to look for.
CPU utilization is 0 while running at this point, and the resource manager shows that it's not doing anything to the disk, memory, or network.
This is on a Windows 10 (fully patched as of 8/30/2017) enterprise system. The code is compiled for .NET Framework 4.6.1. Code Analysis comes up clean.
Are there any other steps I can perform before declaring that the problem is not with my code?
First off, if the issue is not in your code, you still want to learn enough to create a workaround, right?
Some debugging steps you could take:
Create temp variables for the counts and see if you can step past them outside of the if statement:
int tmpListViewCount = listViewAddedKeys.CheckedItems.Count;
int tmpAddedCount = added.Count;
if( tmpListViewCount < tmpAddedCount )
{ // HashFromSelected, etc.. }
Swap tmpListViewCount and tmpAddedCount or use some other method to run tmpAddedCount first.
Try instantiating a .CheckedItems list or extract it from listViewAddedKeys so it is a separate object. Is there a way you can inspect it directly so that you can tell how many objects are in it (i.e. what the count should return with)? Maybe through a breakpoint and mousing over? Try the .count directly on that object. Maybe create a static one that you directly set the list to (not sure what the class is for that).
CheckedItemsClass tmpCheckedItems = listViewAddedKeys.CheckItems;
int tmpListViewCount = tmpCheckedItems.Count;
int tmpAddedCount = added.Count;
if( tmpListViewCount < tmpAddedCount )
{ // HashFromSelected, etc.. }
Setup the UI so that you are calling this function with a static listViewAddedKeys.CheckedItems and added variable that have a defined count that you know ahead of time (1 would be nice...). Maybe make up a button that adds 1 item to each, then call this function so if it succeeds you can manually add more.
I have a feeling the issue is with whatever "CheckedItems" is creating or how that is counted, but not sure. When you count the Checked Items, does that add a count, making an endless loop? Anyway, these should at least show a few debugging methods you might use to break apart and setup your debugging sessions so that you have more control over the situation. Ideally, you know ahead of time what you expect the two counts to be before debugging - have a hypothesis of how you expect these methods to work and what they will return, then you can definitively understand where things are not meeting your expectations. Modify exactly what you are sending into the function after that to see how it changes the response, etc. Basically, apply the scientific method.
I Have this piece of code:
private List<...> LayPrices;
public Decimal BestLayOdds
{
get
{
if (LayPrices.Count > 0)
{
return LayPrices[0].dOdds;
}
return 1000.0M;
}
}
The Problem is that sometimes the List has items, but it does not enter inside the 'if' statement.
Check the images below of a debug session:
How is that even possible?
But if I force it to return the first item, on the last return statement, I get an ArgumentOutOfRangeException even though the list has elements. Check the nest image:
Is there any problem with my code or it is just a stupid bug?
Update:
The LayPrices List is only instantiated on the class Constructor: LayPrices = new List<PriceStruct>();.
It is only getting filled with items on one method, whith the following code:
LayPrices.Clear();
foreach (PriceSize priceSize in exchangePrices.availableToLay)
{
PriceStruct lay = new PriceStruct();
lay.dOdds = (Decimal)priceSize.price;
lay.dAmount = (Decimal)priceSize.size;
LayPrices.Add(lay);
}
Concurrency issues and threading were my first clue, so I did put a lock(LayPrices) and the problem still persisted:
So I think it is not a concurrency issue.
Put Debug.Assert(LayPrices.Count > 0) in the getter before the if statement and you'll see that the List is in fact empty.
The only reasonable explanation is that you are populating the list either in some other thread and you have a race condition or in a property getter that only gets fired by the debugger (you could also be populating the list in a catch clause up the callstack but I imagine you would have figured that out by yourself)
In order to get a better answer please include all code that populates your list. No only the code you think should run, but all the properties, constructors or methods that add or remove items from the list.
I found the problem.
It was indeed concurrency issues, even though I don't use threads explicitly, I use events and I thought event handling was synchronized (It is synchronized right?).
If I add locks everywhere I read or add to the list, the problem disappears.
I am trying to populate a combobox in C#, but for some reason, the items do not appear.
public List<string> items
{
set
{
combobox.Items.Clear();
foreach(string s in value)
{
combobox.Items.Add(s);
}
combobox.Update();
}
}
This seems like incredibly straightforward code. I simply cannot see what is wrong.
It is being called like this:
private void StoreNames(List<string> names)
{
if (selectionForm.InvokeRequired)
selectionForm.Invoke((MethodInvoker)delegate { selectionForm.items = names; });
else
selectionForm.items = names;
}
Interestingly, it seems to work when InvokeRequired returns true, but does not work when it returns false.
EDIT:
I discovered that selectionForm.IsHandleCreated is currently false. This is causing InvokeRequired to return false, but is also why calling the setter regularly isn't working. I don't have any idea why IsHandleCreated is set to false. The Form has been Show()n.
Not sure why your code isn't working - I tried it and it works just fine.
However, below is some more straightforward code which also works - you may find that doing it this way instead makes your problem go away. This does presume that there is not other reason why you need to go through that property - that is quite an unusual way of doing things.
public void StoreNames(List<string> input)
{
if (comboBox1.InvokeRequired)
comboBox1.Invoke((MethodInvoker)delegate {
StoreNames(input);
});
else
{
comboBox1.Items.Clear();
comboBox1.Items.AddRange(input.ToArray());
}
}
Here we just pass the list straight to the items.AddRange() method on the comboBox.
I suspect this won't work for you - something else is going on, but I have tried it both from a backgroundworker (where InvokeRequired is true) and from the main UI thread.
Is it a typo that you refer to both combobox and combobox1? Perhaps that is your error.
Do you mean "not appear" as in you can see them when the list displays, or as in you can't even scroll to them?
Combobox has a lot of properties that can affect what you see. Try a bigger value for combobox.MaxDropDownItems.
My other answer in this thread is really just showing the way to doing this if you can get at the code providing you with the list. Since it sounds like you cannot, I'm providing this answer.
It sounds like the key problem is that when the property is called the combobox has not yet been initialized. The best answer for that is that make sure that this does not happen within the calling code.
If you can't do that then you should wait for the property to be set before you use it to populate the combobox.
I would do this be having a private list which gets set in the property setter. Within the form load event i would then put some code (possibly within a background worker) that will wait until the private list is not null and then assign it to the combobox.
Have a look at this post by Jon Skeet here where he discusses how to correctly wait for a variable to be set by another thread. You will want to be careful when doing this - threading issues can be nasty.
Today, I came across an interesting method of implementing the INotifyPropertyChanged interface. Instead of passing a string name of the property changed, or a lambda expression, we can simply call RaisePropertyChanged(); from the setter, mark that the call is parameterless. This is the code in the RaisePropertyChanged() method:
public virtual void RaisePropertyChanged()
{
var frames = new System.Diagnostics.StackTrace();
for (var i = 0; i < frames.FrameCount; i++)
{
var frame = frames.GetFrame(i).GetMethod() as MethodInfo;
if (frame != null)
if (frame.IsSpecialName && frame.Name.StartsWith("set_"))
{
RaisePropertyChanged(frame.Name.Substring(4));
return;
}
}
throw new InvalidOperationException("NotifyPropertyChanged() can only by invoked within a property setter.");
}
And this is a property that will notify its dependants of its change:
public string MyProperty
{
get { return _myField; }
set
{
_myField= value;
RaisePropertyChanged();
}
}
While I find this approach interesting, I think the performance penalty could be serious in case the property changed often... or if every property in our application used this approach to notify of its change.
I'd like to hear your opinions. (there is no longer the community-wiki checkbox?)
Would this approach be very inefficient?
Source: Article where this approach is presented
I just tested it using this code. (Note that I circumvented the limitation pointed out in Wim Coenen's answer using the MethodImpl attribute. I have my doubts as to whether this is a surefire workaround.)
Results:
Raised event using reflection 1000 times in 25.5334 ms.
Raised event WITHOUT reflection 1000 times in 0.01 ms.
So you can see, the solution involving the stack trace has about 2,500 times the cost of the "normal" solution.
That's the proportional answer, anyway. I personally dislike this idea (clever though it may be) for reasons quite beyond performance issues alone; but, obviously, it's your call.
Edit: For the record, I felt compelled to write a blog post about this—in particular, about the fact that some developers would be tempted to use an approach like this in spite of the performance hit.
Whether you agree with my feelings on the subject or not (I realize that the performance hit is small in absolute terms), I feel that the real killing blow to this idea is that, for it to be even remotely robust, it is necessary to decorate every property setter from which you intend to call RaisePropertyChanged with the MethodImpl attribute, passing MethodImplOptions.NoInlining... which, right there, negates whatever typing savings you otherwise gained.
So you're left with a net loss in development time (by however many seconds it took you to type out the whole MethodImpl attribute part), plus a performance penalty. Very little reason to go this route, if you ask me.
Yeesh, this seems like a lot of work, it'll be slow, and you run the risk of getting the method inlined.
If you want to do this, I'd suggest putting a [MethodImplAttribute] that says not to inline.
My suggestion would be to use a DynamicProxy instead as it'll be much easier and much faster than this approach, the only downside is you must specify the method as virtual. For instance in my work in progress proxy I specify a metaprogramming definition and bind it for my properties, here is my NotifyPropertyChanged interceptor.
private static void SetterInterceptor<T, TProperty>(ProxiedProperty<T, TProperty> property, T target, TProperty value) where T:class,IAutoNotifyPropertyChanged
{
TProperty oldValue;
if (!EqualityComparer<TProperty>.Default.Equals(oldValue = property.GetMethod.CallBaseDelegate(target), value))
{
property.SetMethod.CallBaseDelegate(target, value);
target.OnPropertyChanged(new PropertyChangedEventArgs(property.Property.Name));
}
}
Then it's just a foreach loop across the properties I'm interested in with calls to Delegate.CreateDelegate to perform the binding.
I have no clear proofs, but I believe yes, it would be very costly, especially if every property does this.
Performance doesn't matter, because the linked article states that it doesn't really work:
Apparently this is a method that has
been tried in the past. As Sergey
Barskiy pointed out, the JITter will
likely inline the method and break the
stack frame.
A different approach that I like better is here:
You can get the property name using
reflection on a lambda function that
calls the property getter.
How to raise PropertyChanged event without using string name