Instancing with a dictionary - c#

I am currently working on a project which creates a dictionary with an int index of the instance and a complex type as the value. Since this is a huge school project I do not want to post a ton of code as I have a logic problem rather than a "I need code". I'll try to be as clear as I can and if there is something I need to explain better please let me know.
First off. I have a dictionary in my server:
private Dictionary<int,List<complexType>> dictName = new Dictionary<int,List<complexType>>
Every time a client starts up it registers with the dictionary (i create a blank complex type to instantiate it then i load the dictionary):
List<complexType> temp = null;
dictName.Add(id,temp)
Then when the time comes that I want to add to the list for a particular instance I do this:
complexType myItem = new complexType();
dictName[id].Add(myItem);
When I run this code I get an error when a second client tries to run:
"An unhandled exception of type
'System.Reflection.TargetInvocationException' occurred in
mscorlib.dll. Additional information: Exception has been thrown by the
target of an invocation.
Now this happens when the second user hits:
dictName.Add(id,temp) from the first part.
If i change the instantiation of temp to List<complexType> temp = new List<complexType>();
then it passes that spot but I get the same error again when it updates the clients.
I am currently using this way of passing data with int and string (dictionary)
and they work fine but when I added in a List of a complex type in the dictionary I got the above error.
If anyone has any suggestions I would greatly appreciate it. I'm hoping it has something to do with my initial load of a blank list. If there is anything else you need to know please Ask Thanks!

You are making a dictionary of lists. So you were trying to add to a list that was null and that is what gave you the first exception.
Second, I've never seen the "new private Dictionary" is this a cut and paste typo?
This works:
Dictionary<int, List<string>> dictName = new Dictionary<int, List<string>>();
dictName.Add(0, new List<string>());
dictName[0].Add("First");
dictName.Add(1, new List<string>());
dictName[1].Add("Second");
The fact that you have list of a complex type and I have list of strings shouldn't matter.

Looks like you should initialize the dictionary entry as:
dictName.Add(id, new List<complexType>());
You can also try using the generic Lookup type, which is basically exactly what you need - key to a list of values.
var lookupName = new Lookup<int, complexType>();
lookup.Add(id, new complexType()); // Creates key 'id' and adds new ct.
lookup.Add(id, new complexType()); // Adds new ct to existing key 'id'
lookup.Add(651, null); // Creates key 651 and adds null
So you can just use the add method to add complex type instances to an id key without even thinking of whether the key exists or not.
lookup[id]
Will return you an IEnumerable of the complex types linked to the given id.
Example:
var lu = new Lookup<int, string>();
lu.Add(7, "Seven");
lu.Add(7, "SEVEN");
lu.Add(4, "Four");
lu.Add(7, "7");
lu.Add(4, "FOUR");
lu.Add(4, "FOUR");
Console.WriteLine(string.Join(", ", lu[7])); // "Seven, SEVEN, 7"
Console.WriteLine(string.Join(", ", lu[4])); // "Four, FOUR, FOUR"
foreach (var grp in lu)
{
int id = grp.Key;
foreach (var str in grp)
{
...
}
}

Try this way:
Dictionary<int, List<string>> dictName = new Dictionary<int, List<string>>();
dictName.Add(0, null);
dictName[0] = new List<string>();
dictName[0].Add("Hello");

Related

How to set object value instead of reference?

I've asked that question in a different manner and noone answered me, now I'm asking this with an example, hope It's crystal clear what I'm trying to do.
List<object> l1 = new List<object>() {"string1", "string2"};
Dictionary<string, object> map = new Dictionary<string, object>();
map.Add("aKey", l1[l1.Count - 1]);
object obj = map["aKey"];
What to do with obj in order to change l1[1] value it currently points to?
obj = "newString"; will set obj to "newString" and leave l1[1] - that is "string2" unchanged, because object is a reference type. but I don't want that
Or at least get 1 and l1 out of it.
My whole design is such that I have a storage in the form of two List.
For example you call Engine.Save
Save will get last element from list 2 by default, though if it's given a key as argument it will get the coresponding element from one of the two lists. Than will decide the element's type and save it accordingly or log error message.
I can't easily explain that, nor can I post that much code.
In the dictionary, you could store a reference to the list and the index separately, using tuples:
// Set up the list.
var myList = new List<object>() {"string1", "string2"};
// Set up the dictionary.
var myDict = new Dictionary<string, Tuple<List<object>, int>>();
myDict.Add("myKey", new Tuple<List<object>, int>>(myList, myList.Count - 1));
// Update the list by using the dictionary.
var theTuple = myDict["myKey"];
var theList = theTuple.Item1;
var theIndex = theTuple.Item2;
theList[theIndex] = "newString";

Using Key Value Pair with lists to dynamically create a paired value array

I'm currently using XDocument to read specific attributes from a XML Document, This works without a hitch. Now, I'm trying to create an array with Keys and Values to be later used for Validation. This may be an isolated incident (due to being unable to google/research the errors) , but the error messages which I am experiencing has totally stumped me, the syntax does look correct. The code follows:
public Array GetConfig(string FilePath)
{
var Document = XDocument.Load("CoreConfig.xml");
var Results = Document.Descendants().Elements("Database");
var ReturnList = new List<KeyValuePair<string,string>>();
string[] DBConfigElements = new string[4]{"Server","Username","Password","Database"};
int Count = 1;
var list = new List<KeyValuePair<string, string>>() { // Errors 1,2,3
foreach (string Elements in Results){
new KeyValuePair<string,string>(DBConfigElements[Count],Elements);
Count++;
} // Error 4
};
}
The error messages Presented are:
Error 1 Invalid initializer member declarator
Error 2 ; expected
Error 3 } expected
Error 4 { expected
I have labeled the code which line the error message is being triggered from. The syntax does look correct, so where is it that I am going wrong?
You cannot nest code in a collection initializer like that. If you remember a collection initializer basically calls Add() on the parent for each element it contains, you understand why that isn't possible.
Either format the code so it calls list.Add(new KVP...) in the foreach:
var list = new List<KeyValuePair<string, string>>();
foreach (string Elements in Results)
{
list.Add(new KeyValuePair<string,string>(DBConfigElements[Count], Elements));
Count++;
}
Or use Linq:
var list = Results.Select((element, index) =>
new KeyValuePair<string,string>(DBConfigElements[index], element))
.ToList()
You also might want to use somewhat more meaningful variable names than "list" and "result".
You can't use foreach in an object initializer, but you can use Linq:
var list = new List<KeyValuePair<string, string>>(
Results.Select(r => new KeyValuePair<string,string>(DBConfigElements[Count++],r));

How do I make a generated Object name?

How do I make a generated Object name? For example:
ObjectEx "name" = new ObjectEx();
Edit:
The object will be named by a user input.
The code will be:
Console.Write("Input new user's name: ");
string newUsersName = Console.ReadLine();
(Create ObjectEx)
Edit2:
I have a Dictionary for ObjectEx(Person) which handles all ObjectExs.
Person is the real class name, sorry about making the example object ObjectEx.
public static List<Person> persons = new List<Person>();
Objects don't have names - variables do, and they're always determined at compile-time.
If you want a map from string to object, just use a Dictionary<string, ObjectEx> - then come with random strings using Random. (There are plenty of examples of generating random strings on Stack Overflow.)
If you just want a collection of objects and you were using "random name" as a way of expressing that, use List<ObjectEx> - you don't need a name at all in that case.
If you need something else, please be more specific.
You can use array and store object in to that.
ObjectEx []arrObjectEx = new ObjectEx[10];
arrObjectEx[0] = new ObjectEx();
I would use list<T> (generic list) instead of array if the number of random elements are unknown.
List<ObjectEx> lstObjectEx = new List<ObjectEx>();
lstObjectEx.Add(new ObjectEx());
If randomly generated object need to be accessed uniquely then you can use dictionary. e.g
Dictionary<int, ObjectEx> dicObjectEx = new Dictionary<int, ObjectEx>();
dicObjectEx.Add(someUniqueNumber, new ObjectEx());
That is not possible but how about using a Dictionary. You can use a string value Add and Get hold of an Object you stored.
// somewhere near the start in your code initialize the dictionary
var dict = new Dictionary<string, Person>();
// later on you can dynamically add an Object to the Dictionary
// newUsersName is the so called Index
string newUsersName = Console.ReadLine();
dict.Add(newUsersName, new Person());
// if you need to get hold of that object again use the Index
// myObj is a Person type
var myObj = dict[newUsersName];
// assume Person has an Age property
myObj.Age = 20;
// show all Persons now in the dictionary
foreach(var username in dict.Keys)
{
Console.WriteLine(username);
var pers = dict[username];
Console.WriteLine("{0} is {1} years old", username, pers.Age );
}
You could use a dictionary to store objects, where the Key is the object name

Using the Concurrent Dictionary - Thread Safe Collection Modification

Recently I was running into the following exception when using a generic dictionary
An InvalidOperationException has occurred. A collection was modified
I realized that this error was primarily because of thread safety issues on the static dictionary I was using.
A little background: I currently have an application which has 3 different methods that are related to this issue.
Method A iterates through the dictionary using foreach and returns a value.
Method B adds data to the dictionary.
Method C changes the value of the key in the dictionary.
Sometimes while iterating through the dictionary, data is also being added, which is the cause of this issue. I keep getting this exception in the foreach part of my code where I iterate over the contents of the dictionary. In order to resolve this issue, I replaced the generic dictionary with the ConcurrentDictionary and here are the details of what I did.
Aim : My main objective is to completely remove the exception
For method B (which adds a new key to the dictionary) I replaced .Add with TryAdd
For method C (which updates the value of the dictionary) I did not make any changes. A rough sketch of the code is as follows :
static public int ChangeContent(int para)
{
foreach (KeyValuePair<string, CustObject> pair in static_container)
{
if (pair.Value.propA != para ) //Pending cancel
{
pair.Value.data_id = prim_id; //I am updating the content
return 0;
}
}
return -2;
}
For method A - I am simply iterating over the dictionary and this is where the running code stops (in debug mode) and Visual Studio informs me that this is where the error occured.The code I am using is similar to the following
static public CustObject RetrieveOrderDetails(int para)
{
foreach (KeyValuePair<string, CustObject> pair in static_container)
{
if (pair.Value.cust_id.Equals(symbol))
{
if (pair.Value.OrderStatus != para)
{
return pair.Value; //Found
}
}
}
return null; //Not found
}
Are these changes going to resolve the exception that I am getting.
Edit:
It states on this page that the method GetEnumerator allows you to traverse through the elements in parallel with writes (although it may be outdated). Isnt that the same as using foreach ?
For modification of elements, one option is to manually iterate the dictionary using a for loop, e.g.:
Dictionary<string, string> test = new Dictionary<string, string>();
int dictionaryLength = test.Count();
for (int i = 0; i < dictionaryLength; i++)
{
test[test.ElementAt(i).Key] = "Some new content";
}
Be weary though, that if you're also adding to the Dictionary, you must increment dictionaryLength (or decrement it if you move elements) appropriately.
Depending on what exactly you're doing, and if order matters, you may wish to use a SortedDictionary instead.
You could extend this by updating dictionaryLength explicitly by recalling test.Count() at each iteration, and also use an additional list containing a list of keys you've already modified and so on and so forth if there's a danger of missing any, it really depends what you're doing as much as anything and what your needs are.
You can further get a list of keys using test.Keys.ToList(), that option would work as follows:
Dictionary<string, string> test = new Dictionary<string, string>();
List<string> keys = test.Keys.ToList();
foreach (string key in keys)
{
test[key] = "Some new content";
}
IEnumerable<string> newKeys = test.Keys.ToList().Except(keys);
if(newKeys.Count() > 0)
// Do it again or whatever.
Note that I've also shown an example of how to find out whether any new keys were added between you getting the initial list of keys, and completing iteration such that you could then loop round and handle the new keys.
Hopefully one of these options will suit (or you may even want to mix and match- for loop on the keys for example updating that as you go instead of the length) - as I say, it's as much about what precisely you're trying to do as much as anything.
Before doing foreach() try out copying container to a new instance
var unboundContainer = static_container.ToList();
foreach (KeyValuePair<string, CustObject> pair in unboundContainer)
Also I think updating Value property is not right from thread safety perspectives, refactor your code to use TryUpdate() instead.

C# Dictionary Clear() clears dictionary in dictionary

So I got C# foreach loop which goes like this
foreach(Type s in source)
{
dic1.Clear();
dic1.Add(Key1, s.Attr1);
dic1.Add(Key2, s.Attr2);
...
dic1.Add(KeyN, s.AttrN);
dic2.Add(ind, dic1);
ind++;
}
It gets the values and sets them correctly, no problem in that.
But when the dic1.Clear() is called it clears the dic1 which was added in the dic2
and rewrites the contents of it with the new data being handled resulting N amount of dictionaries with the same data from the last handled data/object. Does the dic1.Clear() really affect the one which was added into the dic2? If it does should I just copy dic1 into dicTemp and add that one into dic2?
Thank you for advance.
I think I get your question now.
When you add a reference object to a collection you are storing a reference to the object, not the value.
What you should do is make dic1 local to the loop body.
foreach(Type s in source)
{
var dic1 = new Dictionary<T1, T2>();
dic1.Add(Key1, s.Attr1);
dic1.Add(Key2, s.Attr2);
...
dic1.Add(KeyN, s.AttrN);
dic2.Add(ind, dic1);
ind++;
}
Since you operate on only one instace through dic1 this will lead to:
All values in dic2 referring to the same dictionary instance
that instance being cleared in the beginning of each iteration.
You probably want to change the line dic1.Clear() to dic1 = new Dictionary<X, Y>().

Categories

Resources