Dictionary error "KeyNotFound" when accessing my accessors - c#

I am getting a
'System.Collections.Generic.KeyNotFoundException' occurred in mscorlib.dll
when i run my code, everthing seems to be fine, i have been unable to find the bug. Here is path of my class caling my get/set
foreach (Tran transaction in transactions)
{
Account sAcc = items[transaction.ID1];//getting error here
Account dAcc = items[transaction.ID2];
decimal tempResult = sAcc.Money - transaction.Amount;
foreach (char s in sAcc.BorP)
Console.WriteLine(s);
And here is my get/set class
public class Tran
{
public int ID1 { get; set; }
public int ID2 { get; set; }
public decimal Amount { get; set; }
}
It was running before and i ran some more test and i keep getting this error and dont know what could be causing int. Thanks for you help

You can use the TryGetValue method of the dictionary.
Here is a sample code of using
object result; // Un-Initialized instance result
myCollection.TryGetValue("Test", out result); // If the key exists the method will out the value
Grabbed from another SO post.
From MSDN's entry on Dictionary.TryGetValue Method:
This method combines the functionality of the ContainsKey method and
the Item property.
If the key is not found, then the value parameter gets the appropriate
default value for the value type TValue; for example, 0 (zero) for
integer types, false for Boolean types, and null for reference types.
Use the TryGetValue method if your code frequently attempts to access
keys that are not in the dictionary. Using this method is more
efficient than catching the KeyNotFoundException thrown by the Item
property.
This method approaches an O(1) operation.
Also reference in this post to lookup the performance of Indexer vs TryGetValue
What is more efficient: Dictionary TryGetValue or ContainsKey+Item?

The issue you are having is that the items you are trying to read from the items array don't exist.
Use either
if (items.ContainsKey(transaction.ID1) && items.ContainsKey(transaction.ID2))
{
// Your code.
} else {
// Signal an error.
}
Or if you have a default account class that you want to use when the transactions do not exist you could use something like this.
if (!items.TryGetValue(transaction.ID1, out sAcc))
items.Add(transaction.ID1, sAcc = new Account);
if (!items.TryGetValue(transaction.ID2, out dAcc))
items.Add(transaction.ID2, dAcc = new Account);
// Your code.
Otherwise if the transaction ID:s should always be in item the problem with your code is likely outside of the code snippets you shared here. I would check what the ID:s are you are trying to look up and do a sanity check.

Related

Why does my allocation get ignored, when setting values to a workitem-field?

I'm trying to automatically create a new workitem, after I choosed the project and one of its workitem-types. For test purposes, I'm iterating over all projects and all of their workitem-types, to create for every workitem-type a new workitem. I know, that there are required fields, which have to have a value, before trying to save that workitem. That's why I'm trying to set "default"-values for that field, but if I log the ArrayList, which I get from the .Validate()-method, I can see, that there are the same fields as before. It seems like my allocation to the fields gets ignored.
In the following example, I would have still the field "GemeldetVon" inside the invalidFields list, at the end.
Does anyone seeing, what I'm doing wrong?
Here is my snippet:
foreach (WorkItemType workItemType in workItemTypes)
{
WorkItem workitem = new WorkItem(workItemType);
workitem.Title = "OTRS-TFS-Connector Test-Workitem";
ArrayList requiredFields = workitem.Validate();
if (requiredFields != null) {
foreach(Field f in requiredFields) {
if (f.Name.Equals("GemeldetVon")) {
workitem.Fields["GemeldetVon"].Value = "some Value";
}
if...
}
}
}
ArrayList invalidFields = workitem.Validate();
IIRC you should call the WorkItem.Open or the WorkItem.PartialOpen method before setting Fields' values.
It's done now. It was because of invalid values, which I tried to assign. My example field needs an user as value, an not just some string. It's working, if I assign valid values. Thanks :)

How can i access Structure property that is inside Hashtable? [duplicate]

This question already has answers here:
Modify Struct variable in a Dictionary
(5 answers)
Closed 7 years ago.
I have the following code that will modify a property inside a structure, and the structure is inside a hash table. Each item in hash table has key of (Int) data type and key of (struct Bag), here is the code i have:
struct Bag {
string apple_type;
string orange_type;
};
// Make a new hashtable that will have a key of (int) data type, value of (Bag)
public static Hashtable bags = new Hashtable();
Then i have a method that will read data from a data base reading rows and adding as long there is a row it will add an item (bag(object)) to the hashtable:
public void initHashtbl(){
OleDbConnection db_connector = new OleDbConnection(connection_string);
// Open connection to oracle
db_connector.Open();
OleDbCommand sql_commander = new OleDbCommand(sql_statement, db_connector);
OleDbDataReader data_Reader = sql_commander.ExecuteReader();
// Read data from sql db server and store it in memory ...
Bag tempBag = new Bag();
// row counter used for list view
int row_counter = 0;
while (data_Reader.Read()) { // Keep reading data from memory until there is no row
tempBag.apple_type = data_Reader[0].ToString();
bags.Add(row_counter, tempBag);
row_counter++;
}
for(int bag_item=0;bag_item < bags.Count;bag_item++){
// Get orange type value from another method that uses another sql statement from another table in db ..
((bag) bags[bag_item]).orange_type = getOrangeType(((bag) bags[bag_item]).apple_type);
}
}
How can i access the property of structure that is already inside hash table at later time if i wanted to access it?
Edit:
I'm getting this error:
"Cannot modify the result of an unboxing conversion."
Dictionary will not allow me to modify that directly
Neither will a Hashtable. This has nothing to do with Hashtable vs Dictionary. The problem is that your "value" in either case is a value type, so you can't modify it directly within the collection. If you really need a struct, then you'll have to create a new value and put it back into the hashtable:
bags.Add(1, new Bag() {apple_type="apple1",orange_type="orange1"});
//((Bag)bags[1]).apple_type="apple2";
var bag = (Bag)bags[1];
bag.apple_type = "appple2";
bags[1] = bag;
But mutable structs are generally bad, so I would either get the value of the struct right the first time (rather than modifying it ourside of the initial load loop) :
// row counter used for list view
int row_counter = 0;
while (data_Reader.Read()) { // Keep reading data from memory until there is no row
{
var appleType = data_Reader[0].ToString();
Bag tempBag = new Bag() {
apple_type = appleType,
orange_type = getOrangeType(appleType)
};
bags.Add(row_counter, tempBag);
row_counter++;
}
or use a class.
Note that the same code works exactly the same way whether you use a Hashtable or a Dictionary.
Also, since your "key" is just an incrementing number (and not tied to the value at all), you could just as well use a List<Bag> and access the items by index.
This code worked for me to read an item:
string orangeType = ((Bag) bags[0]).orange_type;
To modify an item, I think you must create a new Bag and replace the existing one like this:
bags[0] = newBag;
If you try to modify the properties of a bag in the HashTable, then you get the error you reported above.
Because of how value types work, the boxed Bag is a copy of the original, and "unboxing" it by casting back to Bag creates yet another copy. From the C# language spec:
When a value of a value type is converted to type object, an object
instance, also called a “box,” is allocated to hold the value, and the
value is copied into that box. Conversely, when an object reference is
cast to a value type, a check is made that the referenced object is a
box of the correct value type, and, if the check succeeds, the value
in the box is copied out.
Modifying the copy wouldn't change the original anyway, so it wouldn't make much sense to allow it.
Corrections:
To fix your error and to allow modifications to your HashTable of Bag's you should change your value type to reference type:
public class Bag
{
public string apple_type { get; set; }
public string orange_type { get; set; }
};

Retrieved Dictionary Key Not Found

I have a SortedDictionary declared like such:
SortedDictionary<MyObject,IMyInterface> dict = new SortedDictionary<MyObject,IMyInterface>();
When its populated with values, if I grab any key from the dictionary and then try to reference it immediately after, I get a KeyNotFoundException:
MyObject myObj = dict.Keys.First();
var value = dict[myObj]; // This line throws a KeyNotFoundException
As I hover over the dictionary (after the error) with the debugger, I can clearly see the same key that I tried to reference is in fact contained in the dictionary. I'm populating the dictionary using a ReadOnlyCollection of MyObjects. Perhaps something odd is happening there? I tried overriding the == operator and Equals methods to get the explicit comparison I wanted, but no such luck. That really shouldn't matter since I'm actually getting a key directly from the Dictionary then querying the Dictionary using that same key. I can't figure out what's causing this. Has anyone ever seen this behavior?
EDIT 1
In overriding Equals I also overloaded (as MS recommends) GetHashCode as well. Here's the implementation of MyObject for anyone interested:
public class MyObject
{
public string UserName { get; set;}
public UInt64 UserID { get; set;}
public override bool Equals(object obj)
{
if (obj == null || GetType()!= obj.GetType())
{
return false;
}
// Return true if the fields match:
return this.Equals((MyObject)obj);
}
public bool Equals(MyObject other)
{
// Return true if the fields match
return this.UserID == other.UserID;
}
public override int GetHashCode()
{
return (int)this.UserID;
}
public static bool operator ==( MyObject a, MyObject b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
{
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
{
return false;
}
// Return true if the fields match:
return a.UserID == b.UserID
}
public static bool operator !=( MyObject a, MyObject b)
{
return !(a == b);
}
}
What I noticed from debugging is that if I add a quick watch (after the KeyNotFoundException is thrown) for the expression:
dict.ElementAt(0).Key == value;
it returns true. How can this be?
EDIT 2
So the problem ended up being because SortedDictionary (and Dictionary as well) are not thread-safe. There was a background thread that was performing some operations on the dictionary which seem to be triggering a resort of the collection (adding items to the collection would do this). At the same time, when the dictionary iterated through the values to find my key, the collection was being changed and it was not finding my key even though it was there.
Sorry for all of you who asked for code on this one, I'm currently debugging an application that I inherited and I didn't realize this was going on on a timed, background thread. As such, I thought I copied and pasted all the relevant code, but I didn't realize there was another thread running behind everything manipulating the collection.
It appears that the problem ended up being because SortedDictionary is not thread-safe. There was a background thread that was performing some operations on the dictionary (adding items to the collection) which seems to be triggering a resort of the collection. At the same time, when the dictionary was attempting to iterate through the values to find my key, the collection was being changed and resorted, rendering the enumerator invalid, and it was not finding my key even though it was there.
I have a suspicion - it's possible that you're changing the UserID of the key after insertion. For example, this would demonstrate the problem:
var key = new MyObject { UserId = 10 };
var dictionary = new Dictionary<MyObject, string>();
dictionary[key] = "foo";
key.UserId = 20; // This will change the hash code
var value = dict[key]; // Bang!
You shouldn't change properties involved in equality/hash-code considerations for an object which is being used as the key in a hash-based collection. Ideally, change your code so that this can't be changed - make UserId readonly, initialized on construction.
The above definitely would cause a problem - but it's possible that it's not the same as the problem you're seeing, of course.
In addition to overloading == and Equals, make sure you override GetHashCode with a suitable hash function. In particular, see this specification from the documentation:
If two objects compare as equal, the GetHashCode method for each object must return the same value. However, if two objects do not
compare as equal, the GetHashCode methods for the two objects do not
have to return different values.
The GetHashCode method for an object must consistently return the same hash code as long as there is no modification to the object state
that determines the return value of the object's Equals method. Note
that this is true only for the current execution of an application,
and that a different hash code can be returned if the application is
run again.
For the best performance, a hash function should generate an even distribution for all input, including input that is heavily clustered.
An implication is that small modifications to object state should
result in large modifications to the resulting hash code for best hash
table performance.
Hash functions should be inexpensive to compute.
The GetHashCode method should not throw exceptions.
I agree with Jon Skeet's suspicion that you're somehow unintentionally modifying UserID property after it's added as a key. But since the only property that's important for testing equality in MyObject is UserID (and therefore that's the only property that the Dictionary cares about), I'd recommend refactoring your code to use a simple Dictionary<ulong, IMyInterface> instead:
Dictionary<ulong, IMyInterface> dict = new Dictionary<string, IMyInterface>();
ulong userID = dict.Keys.First();
var value = dict[userID];

List<Type> Remove

Somebody explain to me this:
I am trying to delete items from a list with matching ids contained in another list of strings.
Step 1 is as below:
I'm trying to delete Items from myListingSyncIDs where the ListingNumber matches ListingNumbers in lstListingsUpdatedIn24Hrs.
The item at [0] Equals a value from lstListingsUpdatedIn24Hrs, as shown in Step 2:
But as shown in Step3: The Remove fails:
Then After doing a RemoveAll(func) Step4: The Remove works
Somebody explain why the Remove(item) doesn't work, Please ...
Code:
myListingSyncIDs.AddRange(myListingSync.Listings);
#region Remove Listing References Fetched In The Last 24Hrs
// Listing References Fetched In The Last 24Hrs
// These will be excluded to optimise the running of the App.
// Basically meaning that a complete sync of all listings
// will only be done once every 24hrs
// So that if this is run every hr, it will not slow down the most recent additions
List<String> lstListingsUpdatedIn24Hrs = DAL.PropertyPortalDAL.GetSahtWebserviceUpdatesIn24Hrs();
List<P24SyncService.ListingSyncItem> myListingsUpdatedIn24Hrs =
lstListingsUpdatedIn24Hrs.Select(p => new P24SyncService.ListingSyncItem()
{
ListingNumber = p,
Status = P24SyncService.ListingState.AddedModified
}).ToList();
foreach (P24SyncService.ListingSyncItem myLSI in myListingsUpdatedIn24Hrs)
{
myListingSyncIDs.Remove(myLSI);
}
myListingSyncIDs.RemoveAll(p => lstListingsUpdatedIn24Hrs.Contains(p.ListingNumber));
#endregion
ListingSyncItem is:
public partial class ListingSyncItem {
private string listingNumberField;
private ListingState statusField;
/// <remarks/>
public string ListingNumber {
get {
return this.listingNumberField;
}
set {
this.listingNumberField = value;
}
}
/// <remarks/>
public ListingState Status {
get {
return this.statusField;
}
set {
this.statusField = value;
}
}
}
At a guess, your ListingSyncItem type doesn't override Equals, so List<T>.Remove doesn't know that the item to remove is "equal" to the item in your list.
Simply overriding Equals and GetHashCode appropriately (to check for the equality of ListNumber and Status, presumably, and build a hash code based on those) should fix the problem.
For RemoveAll, you're providing a predicate. That doesn't use ListingSyncItem.Equals, which is why it's working.
I can't be sure without seeing the definition of ListingSyncItem, but I'm guessing this has to do with the fact that you have two instances referring to the same item.
You know that two different instances with the same ListingNumber refer to the same conceptual object, but the List<> doesn't. By default, .NET knows two objects are identical if they share the same instance, but since you're creating a new ListingSyncItem in your internal lambda function, it's not being removed.
What you should do is implement IEquatable in your ListingSyncItem class and make it return True for two objects with the same ListingNumber. Then List will know to remove the right items from the list.
As stated, it is because you arent overriding the Equals.
By default, it will check for ref equality. Which, obviously, isnt the case here.
Either override Equals and GetHashCode or use some way of getting the correct reference (lambdas for instance)

C# optimal IDictionary usage for lookup with possibility of not found

Let's say I have a method as follows:
internal MyClass GetValue(long key)
{
if (_myDictionary.ContainsKey(key))
return _myDictionary[key];
return null; // Not found
}
IDictionary<long,MyClass> _myDictionary=...
But the above code has two lookups in the dictionary:
The test for the existance of the key
The actual retrieval of the value
Is there a more optimal way to phrase such a function, so that only one lookup is performed, but the case of "not found" is still handled via a null return (i.e., not via a not found exception)?
For example, it would have been nice if the lookup for the key returned some sort of iterator that could be used to retrieve the value or an invalid iterator if the value was not found as is done in C++. Perhaps C# has a better way of doing this given its language features.
The TryGetValue method was designed for precisely this scenario - to avoid the two lookup operations.
This method combines the functionality of the ContainsKey method and
the Item property.
If the key is not found, then the value parameter gets the appropriate
default value for the value type TValue.
[...] Use the TryGetValue method if your code frequently attempts to access
keys that are not in the dictionary. Using this method is more
efficient than catching the KeyNotFoundException thrown by the Item
property.
internal MyClass GetValue(long key)
{
MyClass maybeValue;
// Normally, one would inspect the return value of this method
// but in this case, it's not necessary since a failed lookup
// will set the out argument to default(valType), which is null
// for a reference type - exactly what you want.
_myDictionary.TryGetValue(key, out maybeValue);
return maybeValue;
}
typing up SPFiredrakes idea ...
public static class Extensions
{
public static TValue GetValueOrDefault<TKey, TValue>(
this IDictionary<Tkey, TValue> iDictionary, Tkey key)
{
TValue result;
return iDictionary.TryGetValue(key, out result) ? result : default(TValue)
}
}
used like this
var d = new Dictionary<long, SomeType>
{{1, new SomeType()}, {42, new SomeType()}, ...}
var value1 = d.GetValueOrDefault(1);
var value42 = d.GetValueOrDefault(42);
var valueX = d.GetValueOrDefault(10);
Of course, you should now check to see if your values are null, which may be why the .Net team omitted this feature.
You should use TryGetValue instead - it uses a single lookup.
internal MyClass GetValue(long key) {
MyClass res = null;
_myDictionary.TryGetValue(key, out res)
return res;
}
The call is short enough to use "inline", without adding a wrapper function. TryGetValue returns a bool indicating if the lookup has been successful or not.

Categories

Resources