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.
Related
I have some weird behaviour with a foreach-loop:
IEnumerable<Compound> loadedCompounds;
...
// Loop through the peaks.
foreach (GCPeak p in peaks)
{
// Loop through the compounds.
foreach (Compound c in loadedCompounds)
{
if (c.IsInRange(p) && c.SignalType == p.SignalType)
{
c.AddPeak(p);
}
}
}
So what I'd like to do: Loop through all the GCPeaks (it is a class) and sort them to their corresponding compounds.
AddPeak just adds the GCPeak to a SortedList. Code compiles and runs without exceptions, but the problem is:
After c.AddPeak(p) the SortedList in c contains the GCPeak (checked with Debugger), while the SortedLists in loadedCompounds remains empty.
I am quite confused with this bug I produced:
What is the reason for this behavior? Both Compound and GCPeak are classes so I'd expect references and not copies of my objects and my code to work.
How to do what I'd like to do properly?
EDIT:
This is how I obtain the IEnumarables (The whole thing is coming from an XML file - LINQ to XML). Compounds are obtained basically the same way.
IEnumerable<GCPeak> peaksFromSignal = from p in signal.Descendants("IntegrationResults")
select new GCPeak()
{
SignalType = signaltype,
RunInformation = runInformation,
RetentionTime = XmlConvert.ToDouble(p.Element("RetTime").Value),
PeakArea = XmlConvert.ToDouble(p.Element("Area").Value),
};
Thanks!
An IEnumerable won't hold a hard reference to your list. This causes two potential problems for you.
1) What you are enumerating might not be there anymore (for example if you were enumerating a list of facebook posts using a lazy technique like IEnumerable etc, but your connection to facebook for is closed, then it may evaluate to an empty enumerable. The same would occur if you were doing an IEnumerable over a database collection but that DB connection was closed etc.
2) Using an enumerable like that could lead you later to or previously to that to do a multiple enumeration which can have issues. Resharper typically warns against this (to prevent unintended consequences). See here for more info: Handling warning for possible multiple enumeration of IEnumerable
What you can do to debug your situation would be to use the LINQ extension of .toList() to force early evaluation of your IEnumerable. This will let you see what is in the IEnumerable easier and will let you follow this through your code. Do note that doing toList() does have performance implications as compared to a lazy reference like you have currently but it will force a hard reference earlier and help you debug your scenario and will avoid scenarios mentioned above causing challenges for you.
Thanks for your comments.
Indeed converting my loadedCompounds to a List<> worked.
Lesson learned: Be careful with IEnumerable.
EDIT
As requested, I am adding the implementation of AddPeak:
public void AddPeak(GCPeak peak)
{
if (peak != null)
{
peaks.Add(peak.RunInformation.InjectionDateTime, peak);
}
}
RunInformation is a struct.
I got an ObservableCollection (Zone class contains a IsFiltered boolean property) on which several items got theirs IsFiltered property set to true.
For a few cases, I need to unilateraly remove all filters (i.e. set IsFiltered prop to false for all ObservableCollection items).
Is there a way to achieve this the way ObservableCollection.Single(LINQ request) do it, or do I have to loop on my ObservableCollection to set this prop to false on all items?
Thanks for your answer !
You'll have to loop but at least restrict your loop to the objects that need resetting:
foreach(var zone in zones.Where(z => z.IsFiltered))
{
zone.IsFiltered = false;
}
As other answers/comments have mentioned, avoid Linq for the update. See Jon Skeet's answer https://stackoverflow.com/a/1160989/1202600 - Linq is for querying, not updating.
I am not sure if this is what you are looking for, but Lists in C# got ForEach method which kind of does what you want, so:
myObservableCollection.ToList().ForEach(x => x.MyFlag = false);
Posting my thoughts (since you haven't accepted any answer as yet - please consider if you have moved on)
There is no other way than iterating through 'ObservableCollection'. You may find APIs (linq) to do that for you, but in the end it has to iterate through all objects to update their state.
If your collection is updated by other threads then you need to consider thread safety also (it will through exception if other thread updates while you are iterating to update IsFiltered)
Other point is updating a property doesn't reflect in binded UI unless that property raises 'NotifyPropertyChanged' event. So your object should have something like below:
public bool IsFiltered{
get { return _isFiltered; }
set {
if (_isFiltered == value) return; //no need to modify and trigger UI update
_isFiltered = value;
}
I have inherited some code. I see that this code exists:
private List<int> Data { get; set; }
private CsClipboard()
{
Data = new List<int>();
}
public List<int> ComponentIDs
{
get
{
return Data;
}
set
{
Data.Clear();
Data = value;
}
}
I don't see any reason to call clear before setting Data to value. I'm wondering if there are scenarios in C# where I would want to call clear before setting the value aside from something like triggering an OnClear event. It's a fairly large code base with tech. debt, so just being overly cautious.
That code could have some nasty side affects.
What happens there is that the original list gets cleared. so every other place in the code that holds the original list will now hold an empty list.
Every new get request will hold the new list. But the the data isn't concurrent across the program.
In general, you should avoid public properties that return a mutable list. Once a consumer gets a reference to it, you no longer have a guarantee on the state of what should be an internal detail. Clearing the list in a setter only exacerbates the issue, because now you are clearing a list that a consumer might still have a reference to (even though it is no longer the correct list.)
You should consider changing the property so that it returns a copy (preferably read-only) of the current state of the list. The AsReadOnly() method can help here. If you can't do that, at least don't clear the list before setting the new value.
I would want to call clear before setting the value aside from
something like triggering an OnClear event.
The List class does not have events MSDN
So how about writing you own custom Clear method for the list
I mean extension method for the list class that will use your Clear method with your custom logic
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.
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.