I am having trouble trying to iterate over a dictionary passed to a function as a generic. For example, I have a function that loads data from a DB.
public T Load<T>(...)
This function can be called like so, with which I have no problems;
someclasstype data = Load<someclasstype>(...);
List<someclasstype> data = Load<List<someclasstype>>(...);
I've recently tried to extend this to be able to deal with dictionaries as well, and calling it like so:
Dictionary<long, someclasstype> data = Load<Dictionary<long, someclasstype>>(...)
I can load the data without a problem and store it in the dictionary no problem.
At this stage, the dictionary, with all its keyvaluepairs is stored in a variable called result, and I'm creating an IEnumerable with
IEnumerator resultIdx = ((IEnumerable)result).GetEnumerator();
if (!resultIdx.MoveNext())
return (T)result;
object kvp = resultIdx.Current;
So far so good. I can see the value of the key and the value of the value in a watch, or by mouseover on the kvp variable.
But I cannot figure out how to get the value part of the keyvaluepair from kvp.
// None of these work - I get compile time errors, unboxing errors, or invalid cast errors.
object item = ((KeyValuePair<TKey, TValue>)kvp).Value;
object item = ((KeyValuePair<long, object>)kvp).Value;
object item = ((T)kvp).Value // Never had a hope for this, but desperation...
Does anyone have any idea how I can do this?
try adding dynamic kvp = resultIdx.Current; . Then you can use kvp.Value
You can rewrite the function into two functions like.
public T Load<T>(...)
//Or maybe public List<T> Load<T>(...)
and
public Dictionary<long, T> LoadD<T>(...)
Then you can cast result to KeyValuePair<long, T> in LoadD. You can call Load from LoadD to minimize code rewriting.
Answer provided by Dede in comments:
"Use Reflection ?
object key kvp.GetType().GetProperty("Key").GetValue(kvp);
object value kvp.GetType().GetProperty("Value").GetValue(kvp);
Not very optimized, but can work... – Dede 24"
Related
I need a data structure like below, but I need to be able to change the bool value. Other two stay the as they were when they were initialized. What would you use for best performance?
Dictionary<string, (object, bool)> dic = new Dictionary<string, (object, bool)>();
I was thinking of hashtable. But hashtable is like a dictionary with key/value. The object and bool in my example are in concept not like a key/value, because other values of the external dictionary can have the same object (or better yet ... object type). I don't want to make someone looking at my code later on thinking that the object and bool are more related they really are.
EDIT: object in this example is just a place holder. In reality it's a complex object with other objects in it and so on. Procedure before this one makes a bunch of this objects and some of them are deepcopy of the others. They are passed to this procedure. All of the object are here named by some rules and stored in the dictionary. Names are obviously unique. Procedure that comes after will take this dictionary and set the bool value on and off based on the values in the objects themselves and on the values of other bools. Procedure will be recursive until some state is reached.
Number of objects (or dic. entries) is arbitrary but expected to be >100 && <500. Time complexity is O(n).
I am targeting .NET7 (standard).
but I need to be able to change the bool value.
You can just reassign value for the key:
var tuples = new Dictionary<string, (object Obj, bool Bool)>
{
{ "1", (new object(), true) }
};
tuples["1"] = (tuples["1"].Obj, false); // or tuples["1"] = (tuples["1"].Item1, false);
Or
if (tuples.TryGetValue("1", out var c))
{
tuples["1"] = (c.Obj, false);
}
Personally I would leave it at that, but for really high perf scenarios you can look into CollectionMarshall instead of second snippet:
ref var v = ref CollectionsMarshal.GetValueRefOrNullRef(tuples, "1");
if (!Unsafe.IsNullRef(ref v))
{
v.Bool = false;
}
A bit more info - here.
For the 'performance' aspect:
The .NET Dictionary uses hashes to look up the item you need, which is very fast (comparable to a HashTable). I don't expect much performance issues related to this, or at least nothing that can be improved on with other data structures.
Also, you shouldn't worry about performance unless you are doing things a million times in a row + it turns out (in practice) that something is taking a measurable amount of time.
For the 'changing a bool' aspect:
... that is quite a long story.
There are 2 tuple variants in .NET:
The value tuple, created by doing var x = (myObj, myBool), like you are doing.
The x is a struct, and therefore a Value Type. You can actually change x.Item1 or x.Item2 to a new value just fine.
However... if you put x into a Dictionary then you actually put a copy of x (with a copy of its values) into the dictionary, because that is the nature of value types.
When you retrieve it again from the Dictionary, yet another copy is made - which makes modifying the actual tuple inside the Dictionary impossible; any attempt to do so would only modify the last copy you got.
Side story: The .NET Compiler knows this, which is why its refuses to compile code like dic[yourKey].Item2 = newBool; because such code wouldn't do what you might hope it would do. You're basically telling the compiler to create a copy, modify the copy, and then... discard the copy. The compiler requries a variable to store the copy before the rest can even start, but we provided no variable.
The Tuple generic class, or rather a range of generic classes, an instance of which can be created using calls like var x = Tuple.Create(myObj, myBool). These classes however forbid that you change any of their properties, they are always readonly. Tuple class instances can be put in a Dictionary, but they will still be readonly.
So what options are there really to 'modify a value in a tuple' a Dictionary?
Keep using a value tuple, but accept that in order to "change" the tuple inside the Dictionary you'll have to make a new instance (either a copy, or from scratch), set it to the properties that you want, and put that instance (or actualy a copy...) into the dictionary:
// initialize it
var dict = new Dictionary<string, (object, bool)>();
var obj = new object();
dict["abc"] = (obj, true);
// change it
var tmpTuple = dict["abc"]; // get copy
tmpTuple.Item2 = false; // alter copy
dict["abc"] = tmpTuple; // store another copy
// or if you want to avoid the tmp variable
dict["abc"] = (dict["abc"].Item1, false)
Use a custom class instead of the value tuple or a Tuple class, and then put that into the Dictionary:
public class MyPair
{
public object O { get; set; }
public bool B { get; set; }
}
// initialize it
var dict = new Dictionary<string, MyPair>();
var obj = new object();
dict["abc"] = new MyPair { O = obj, B = true };
// change it
dict["abc"].B = false;
So both types of Tuples are OK for objects that you don't want to do a lot with. But both have certain limits in their usage, and sooner or later you may need to start using classes.
I am currently struggling to create a dictionary. I want to create it so that it can be used in multiple situations. However, these situations vary from key and value types. So while you normally do:
Dictionary<int, string> Something = new Dictionary<int, string>();
I want to do something like:
Dictionary<variable1, variable2> ..............
Doesn't matter much what variable1 is. It can be a string, that stores 'string', or 'int' as value. I could also use variable1.getType() to determine the type. Either way would work for me. But the way I did above, well, that is just incorrect. There must be another way to set the key and value type based on variables... right?
Something just shoot into my head, to use if's to check what the type is, and based on the type make the dictionary use that type. But with the amount of types, it's going to be a lot of if's, and I feel like there has to be a better way.
Searching hasn't helped me much. Well I learned some other things, but no solution to my problem. In every single case, dictionary TKey and TValue has been set manually. While I want to set them, with a variable that I take from some source.
There must be another way to set the key and value type based on
variables... right?
Yes, there is. You can make a helper method that creates a dictionary, example:
public static Dictionary<K, V> CreateDictionaryFor<K, V>(K key, V value)
{
return new Dictionary<K, V>();
}
Then, you can use it with variable1 and variable2:
var dictionary = CreateDictionaryFor(variable1, variable2);
You can try doing Dictionary<object, object>.
That way you can pass whatever you need to pass and check the type as needed.
var dict = new Dictionary<object, object>();
dict.Add(45, "dkd");
A pssibility would be to capsulate the dictionary in a new class, and create the dictionary via a generic method:
public class GenericDictionary
{
private IDictionary m_dictionary;
public bool Add<TA, TB>(TA key, TB value)
{
try
{
if (m_dictionary == null)
{
m_dictionary = new Dictionary<TA, TB>();
}
//check types before adding, instead of using try/catch
m_dictionary.Add(key, value);
return true;
}
catch (Exception)
{
//wrong types were added to an existing dictionary
return false;
}
}
}
Of course the code above needs some improvements (no exception when adding wrong types, additional methods implementing the dictionary methods you need), but the idea should be clear.
I do DataBinding in the following way
private List<MyEditor> Editors { get; set; }
private Dictionary<int,object> dictionary
private void SetEditors()
{
Editors.Clear();
foreach (var element in dictionary)
{
var editor = MyFactory.GetEditor();
editor.DataBindings.DefaultDataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
editor.DataBindings.Add("Value", element, "Value");
//some code
Editors.Add(editor);
}
//some more code
}
Then in GUI I do some changes to Value of Editors[0], after that in another piece of code I try to get value from dictionary element and find out that it hasn't changed, even though I use Editors[0].DataBindings["Value"].WriteValue() to ensure data is written to dictionary.
In debugger I can see the following picture:
Editors[0].DataBindings["Value"] {System.Windows.Forms.Binding} System.Windows.Forms.Binding
....
DataSource {[0, oldValue]} object {System.Collections.Generic.KeyValuePair<int,object>}
....
while
Editors[0].Value "newValue" object {string}
What could it be? Will be grateful for any ideas.
I'm not certain I'm following correctly, but I believe the answer is that when you enumerate a Dictionary, the KeyValuePair (KVP) objects you get are created at the time of the enumeration. Enumerate it again and you will get a different set of objects. This is because a KVP is a value type.
To alter something referred to by a KVP, you have to return to the original Dictionary object. A data binding does not do that.
In the case where Dictionary<object, object> myDictionary happens to contain a single item, what is the best way to retrieve the value object (if I don't care about the key) ?
if (myDictionary.Count == 1)
{
// Doesn't work
object obj = myDictionary.Values[0];
}
Thanks
Depending on wether you want it to fail if there's multiple object or not you can use either
myDictionary.Value.Single();//Will fail if there's more than one
or
myDictionary.Value.First();//Will just return the first regardless of the count
object obj = myDictionary.Values.Single();
I would never code for the assumption that there will only be one. If you know there's always going to be exactly one, then why use a dictionary?
You can't get the value directly or by index, you have to either know the key:
object obj = yourDictionary[theKeyThatYouHappenToKnow];
or use an enumerator:
var en = yourDictionary.GetEnumerator();
en.MoveNext();
object obj = en.Current.Value;
en.Dispose();
If you are using framework 3.5, you can also some extension method like Single or First to use the enumerator for you.
I think you can use an iterator.
myDictionary.GetEnumerator().Current
I have an ICollection that I know will only ever have one member. Currently, I loop through it, knowing the loop will only ever run once, to grab the value. Is there a cleaner way to do this?
I could alter the persistentState object to return single values, but that would complicate the rest of the interface. It's grabbing data from XML, and for the most part ICollections are appropriate.
// worldMapLinks ensured to be a singleton
ICollection<IDictionary<string, string>> worldMapLinks = persistentState.GetAllOfType("worldMapLink");
string levelName = ""; //worldMapLinks.GetEnumerator().Current['filePath'];
// this loop will only run once
foreach (IDictionary<string, string> dict in worldMapLinks) // hacky hack hack hack
{
levelName = dict["filePath"];
}
// proceed with levelName
loadLevel(levelName);
Here is another example of the same issue:
// meta will be a singleton
ICollection<IDictionary<string, string>> meta = persistentState.GetAllOfType("meta");
foreach (IDictionary<string, string> dict in meta) // this loop should only run once. HACKS.
{
currentLevelName = dict["name"];
currentLevelCaption = dict["teaserCaption"];
}
Yet another example:
private Vector2 startPositionOfKV(ICollection<IDictionary<string, string>> dicts)
{
Vector2 result = new Vector2();
foreach (IDictionary<string, string> dict in dicts) // this loop will only ever run once
{
result.X = Single.Parse(dict["x"]);
result.Y = Single.Parse(dict["y"]);
}
return result;
}
Why not use the Single or FirstOrDefault extension methods?
var levelName = worldMapLinks.Single().Value;
Single has the advantage of enforcing your assumption that there is only 1 value in the enumeration. If this is not true an exception will be raised forcing you to reconsider your logic. FirstOrDefault will return a default value if there is not at least 1 element in the enumeration.
If you can use LINQ-to-objects in your class, use the Single() extension method on the collection if you know there will be exactly one member. Otherwise, if there could be zero or one, use SingleOrDefault()
Why do you have a collection with only one member? It seems that the real answer should be to better design your system rather than rely on any method to retrieve one element from a collection. You say it makes it more complicated, but how? Isn't this solution itself a complication? Is it possible to change the interface to return one element where applicable and a collection elsewhere? Seems like a code smell to me.