I'm considering three approaches for returning references to internal Dictionary instances (C#) in regards to code safety and impact on the code readability/visually for a project I'm working on.
I've narrowed it down to the following three approaches, but am open to better suggestions. Currently I prefer #3 as the best balance of safety without extra boiler plate.
1) Use a second ReadOnlyDictionary instance to wrap internal Dictionary, only ever letting the ReadOnlyDictionary escape the class:
2) Return the Dictionary instance as an IReadOnlyDictionary, but recasting would allow it to be modified so not as safe as option #1 or #3.
3) Return Dictionary.ToImmutableDictionary() as a ImmutableDictionary when it escapes the containing class so that the returned object is an immutable view of the inner dictionary, although this will make a new copy for every call incurring a higher cost, that should be fine with small simple dictionaries (which mine are).
private readonly Dictionary<string, string> innerDictionary = new Dictionary<string, string>();
// Only required for Example #1
private readonly IReadOnlyDictionary<string, string> readonlyInnerDictionary;
public ExampleClass() {
// Only required for Example #1
readonlyInnerDictionary = new ReadOnlyDictionary<string, string>(innerDictionary);
}
public IReadOnlyDictionary<string, string> GetExampleOne() {
// Requires a second dictionary which is more boiler plate but the object being returned is truly readonly
return readonlyInnerDictionary;
}
public IReadOnlyDictionary<string, string> GetExampleTwo() {
// Requires InnerDictionary be defined as Dictionary (Not IDictionary) but doesn't require the second dictionary be defined
// which is less boiler plate, but the object returned could be re-cast to it's mutable form meaning it's not truly mutation safe.
return innerDictionary;
}
public ImmutableDictionary<string, string> GetExampleThree() {
// Truly immutable object returned, but a new instance is built for every call; fortunately all of my dictionaries are small (containing at most 9 keys)
return innerDictionary.ToImmutableDictionary();
}
Option 1 is the way to go. You can recast ReadOnlyDictionary to IDictionary, but that will throw an Exception when trying to mutate:
void CastingTest()
{
var dic1 = new Dictionary<string, string>();
dic1.Add("Key", "Value");
var dic2 = new ReadOnlyDictionary<string, string>(dic1);
var castedDic = (IDictionary<string, string>)dic2;
castedDic.Add("AnotherKey", "Another Value"); //System.NotSupportedException, Collection is read only
}
The ReadOnlyDictionary doesn't create another Dictionary. It points to the same reference of the first one, encapsulating it. So if you do:
void AddTest()
{
var dic1 = new Dictionary<string, string>();
dic1.Add("Key", "Value");
var dic2 = new ReadOnlyDictionary<string, string>(dic1);
dic1.Add("Key2", "Value2"); //Now dic2 have 2 values too.
}
Never expose your innerDictionary and you'll be fine.
Determined that the neatest, easiest and safest; but not the most performant solution is to use a ConcurrentDictionary internally which ensures thread safety (from System.Collections.Concurrent) and then to use the System.Collections.Immutable to call dictionary.ToImmutableDictionary() which creates the dictionary which escapes the inner class. The interface signature is for ImmutableDictionary<KeyType, ValueType>.
This is not the most performant solution, but in my case with dictionaries with less than 12 keys and small simple objects representing state in most cases that is not a concern.
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 working with an existing C# codebase that is initializing a lot of objects using what seems to be a generic new() command that doesn't include the object type. I am coming from Java to C#, and I have always used the = new Object() approach.
Here are the two different approaches for creating objects in the code. Both appear to be used inconsistently through the codebase.
var object1 = new Object();
Object object2 = new();
I have read up creating anonymous objects in C# using the syntax new{ } but I can't find much on just using new with parens for initialization.
All the code is doing at this point is initializing new instances of these objects for later use. Following the debugger through, it appears as if both approaches result in identical objects. However, is it truly the case that both approaches are equivalent? Is there any reason why I should be using one of these approaches versus the other, either technically or as a best practice professionally?
The end result is absolutely the same IL code. So if we are talking about any performance difference - there is no difference. It's just a "syntax sugar" to let us write code more conveniently.
As for what is worth to use, first of all, use that way which is already used in your project. Don't mix up different styles. If you've just started your project then as for me it's better to use the full name of a type, it's easier to read and understand. But it's on you, you can google any C# Coding Conventions and follow it throughout the project.
var is kind of a placeholder. If the object-type is known to the compiler you may use var as a placeholder. I personally try to not use it too often as I find the coding to be less clear and debugging harder.
Example:
Dictionary<string, int> dict = new Dictionary<string, int>();
var dict = new Dictionary<string, int>();
similarly (beginning from C# 9.0), the object type may be omitted from object creation if the variable-type is known:
Dictionary<string, int> dict = new Dictionary<string, int>();
Dictionary<string, int> dict = new ();
To conclude:
In your case, where empty objects are newly created in variables, it does not make a difference. They both do exactly the same, they are just switched vice versa. It is merely a convenience feature. That beeing said, a convenience feature while writing code, but a pain when coming back to a project and trying to understand whats going on.
# all the same:
Dictionary<string, int> dict = new Dictionary<string, int>();
var dict = new Dictionary<string, int>();
Dictionary<string, int> dict = new ();
However, in code you would use var for creating a new variable while using new() for assigning a new empty object to a variable:
# creates variable Object[] and assigns a value
var inhabitants = allInhabitants.ToArray();
# assigns an empty object to variable
Object[] inhabitants = new();
More details here:
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/new-operator
As it was told already it is C# 9's new feature. It is a matter of style to use or not to use it, code behind will be absolutely the same. But be carefull, I noticed a small syntax pitfall , but it also shows the difference between the anonymos types and this new c# feature
var list = new List<int> {1,2,3,4}; //OK
List<int> list = new List<int> {1,2,3,4}; //OK
List<int> list = new() {1,2,3,4}; //OK
List<int> list = new {1,2,3,4}; // Error, anonymos type !!!
I am in this situation that there is a large dictionary that is randomly updated by one thread at a fairly high frequency, and there is another thread that tries to take a snapshot of the dictionary to save as history.
I currently using something like this:
Dictionary<string, object> dict = new Dictionary<string, object>();
var items = dict.Values.ToList();
This works fine for most of the time, except it occasionally throws:
System.InvalidOperationException: Collection was modified; enumeration
operation may not execute.
I understand why this happen, but I don't know what can I do to avoid the collection modified error.
What is the best approach to iterate such collection?
I also tried ConcurrentDictionary, but no luck.
Why? Is ConcurrentDictionary thread safe only at item level?
According to the docs you should be able to use the GetEnumerator() method of ConcurrentDictionary to get a thread-safe iterator.
The enumerator returned from the dictionary is safe to use concurrently with reads and writes to the dictionary, however it does not represent a moment-in-time snapshot of the dictionary. The contents exposed through the enumerator may contain modifications made to the dictionary after GetEnumerator was called.
Since you're dealing with concurrent threads, it's not surprising to have some tradeoffs with consistency, but I would expect this approach to block less than the brute force approach given in other answers. This wouldn't have worked if you tried:
var items = concurrentDict.Items.ToList();
but it's supposed to work for
var items = concurrentDict.GetEnumerator();
or you could simply reference the iterator directly:
foreach(var item in concurrentDict)
{
valueList.Add(item.Value);
}
An ImmutableDictionary might be appropriate for you, as it supports scalable multi-threading and snapshotting as part of its basic feature-set.
// initialize.
ImmutableDictionary<string, int> dict = ImmutableDictionary.Create<string,int>();
// create a new dictionary with "foo" key added.
ImmutableDictionary<string, int> newdict = dict.Add("foo", 0);
// replace dict, thread-safe, with a new dictionary with "bar" added.
// note this is using dict, not newdict, so there is no "foo" in it.
ImmutableInterlocked.TryAdd(ref dict, "bar", 1);
// take a snapshot, thread-safe.
ImmutableDictionary<string,int> snapshot = dict;
The immutable nature means that the dictionary can never change -- you can only add a value by creating a new dictionary. And because of this property, you take a "snapshot" of it by simply keeping a reference around from the point you want to snapshot.
It is optimized under the hood to be efficient, not copying the entire thing for every operation. That said, for other operations it isn't as efficient as ConcurrentDictionary, but it's all a trade-off in what you want. For instance, a ConcurrentDictionary can be concurrently enumerated but it's impossible to enumerate a snapshot of it.
You can use a monitor with lock keyword to ensure that only reading or only writing is executing at this moment.
public class SnapshotDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
private readonly Dictionary<TKey, TValue> _dictionary = new Dictionary<TKey, TValue>();
private readonly object _lock = new object();
public void Add(TKey key, TValue value)
{
lock (_lock)
{
_dictionary.Add(key, value);
}
}
// TODO: Other necessary IDictionary methods
public Dictionary<TKey, TValue> GetSnaphot()
{
lock (_lock)
{
return new Dictionary<TKey, TValue>(_dictionary);
}
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return GetSnaphot().GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
GetSnapshot method returns a snapshot of your dictionary.
I have also overriden GetEnumerator so that it creates a snapshot and then returns snapshot's enumerator.
So, this will work because will be executed on a snapshot:
var items = snapshotDictionary.GetSnapshot().Values.ToList();
// or
foreach (var item in snapshotDictionary)
{
// ...
}
However, this approach does not allow multithreading writing.
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.
If I have a Dictionary<String,...> is it possible to make methods like ContainsKey case-insensitive?
This seemed related, but I didn't understand it properly: c# Dictionary: making the Key case-insensitive through declarations
This seemed related, but I didn't understand it properly: c# Dictionary: making the Key case-insensitive through declarations
It is indeed related. The solution is to tell the dictionary instance not to use the standard string compare method (which is case sensitive) but rather to use a case insensitive one. This is done using the appropriate constructor:
var dict = new Dictionary<string, YourClass>(
StringComparer.InvariantCultureIgnoreCase);
The constructor expects an IEqualityComparer which tells the dictionary how to compare keys.
StringComparer.InvariantCultureIgnoreCase gives you an IEqualityComparer instance which compares strings in a case-insensitive manner.
var myDic = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
myDic.Add("HeLlo", "hi");
if (myDic.ContainsKey("hello"))
Console.WriteLine(myDic["hello"]);
There are few chances where your deal with dictionary which is pulled from 3rd party or external dll. Using linq
YourDictionary.Any(i => i.KeyName.ToLower().Contains("yourstring")))
If you have no control in the instance creation, let say your object is desterilized from json etc, you can create a wrapper class that inherits from dictionary class.
public class CaseInSensitiveDictionary<TValue> : Dictionary<string, TValue>
{
public CaseInSensitiveDictionary() : base(StringComparer.OrdinalIgnoreCase){}
}
I just ran into the same kind of trouble where I needed a caseINsensitive dictionary in a ASP.NET Core controller.
I wrote an extension method which does the trick.
Maybe this can be helpful for others as well...
public static IDictionary<string, TValue> ConvertToCaseInSensitive<TValue>(this IDictionary<string, TValue> dictionary)
{
var resultDictionary = new Dictionary<string, TValue>(StringComparer.InvariantCultureIgnoreCase);
foreach (var (key, value) in dictionary)
{
resultDictionary.Add(key, value);
}
dictionary = resultDictionary;
return dictionary;
}
To use the extension method:
myDictionary.ConvertToCaseInSensitive();
Then get a value from the dictionary with:
myDictionary.ContainsKey("TheKeyWhichIsNotCaseSensitiveAnymore!");
I know this is an older question, but I had the same issue where the dictionary is coming from a 3rd party tool that did not implement an ignore case StringComparer in the constructor. Tweaked from the method #Soviut has above, but feel this is a lot cleaner and lets you work with the value immediately.
var lookup = source.FirstOrDefault(x => x.Key.Equals("...", StringComparison.OrdinalIgnoreCase));
if (lookup.Key != null)