I'm trying to write an extension method for dictionaries to shorten the TryGetValue syntax.
This is the extension and the exact same logic in a normal method.
private static List<T> TryGet<T>(this Dictionary<int, List<T>> dict, int key)
{
return dict.TryGetValue(key, out var output) ? output : new List<T>();
}
private static List<T> TryGet<T>(Dictionary<int, List<T>> dict, int key)
{
return dict.TryGetValue(key, out var output) ? output : new List<T>();
}
var works = TryGet(MyDict, MyInt);
var doesntWork = MyDict.TryGet...
The code simply does not find the extension. I made triple sure that the dictionary is the same and of the right type.
I have the extension code in a file with other working extensions, so that's not the problem either.
The extension methods needs to be accessible for the calling method and should be defined in a static class. In the OP, it is likely that it was defined in a non-static class
public static class Extensions
{
public static List<T> TryGet<T>(this Dictionary<int, List<T>> dict, int key) {
return dict.TryGetValue(key, out var output) ? output : new List<T>();
}
}
Extension methods must be accessible by the caller and in a static class.
public static class Extensions
{
public static List<T> TryGet<T>(this Dictionary<int, List<T>> dict, int key) {
return dict.TryGetValue(key, out var output) ? output : new List<T>();
}
}
Related
I have a dictionary of type
Dictionary<int, (float, float)>
when trying to read the value from it I can't use this way
if (myDict.TryGetValue(1, out (float tupleItem1, float tupleItem2))) { /* ... */ }
because then I get compile errors
The way it works is
if (myDict.TryGetValue(1, out (float, float) theTuple)) { /* ... */ }
Is there a way I can directly initialize the variables like so?
if (!myDict.TryGetValue(1, out (float tupleItem1, float tupleItem2)))
{
/* handle if not found */
tupleItem1 = 111;
tupleItem2 = -12345;
}
You can't deconstruct directly in an out parameter yet unfortunately, see this proposal.
You'll have to deconstruct it yourself:
if (!myDict.TryGetValue(1, out var result))
{
result = (111, -12345);
}
You can improve this situation slightly with an extension method:
public static class DictionaryExtensions
{
public static TValue? TryGetValue<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key) where TValue : struct
{
return dict.TryGetValue(key, out var result) ? result : null;
}
}
This lets you write:
if (myDict.TryGetValue(1) is not (float tupleItem1, float tupleItem2))
{
tupleItem1 = 111;
tupleItem2 = -12345;
}
If you find yourself doing this a lot, you could write a simple little extension method to make it more readable:
public static class DictionaryExt
{
public static TValue TryGetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, Func<TValue> getDefault)
{
return dict.TryGetValue(key, out var value)
? value
: getDefault();
}
}
Then your sample code could looks something like this:
var dict = new Dictionary<int, (float, float)>();
var result = dict.TryGetValueOrDefault(1, () => (111, -12345));
Console.WriteLine(result);
I chose to use Func<TValue> rather than TValue for the default so that you don't have to create a default value that isn't going to be used in the case that the dictionary already contains the key.
If you want a slightly simpler syntax and you don't care that the default is created for every call regardless of whether it's actually needed you could write it like this instead:
public static class DictionaryExt
{
public static TValue TryGetValueOrDefault<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue defaultValue)
{
return dict.TryGetValue(key, out var value)
? value
: defaultValue;
}
}
Which would be called like this:
var dict = new Dictionary<int, (float, float)>();
var result = dict.TryGetValueOrDefault(1, (111, -12345));
Console.WriteLine(result);
You could of course include both methods in DictionaryExt for more flexibility.
(It's also entirely possible that the overhead of creating a Func<TValue> for every call is greater than creating a tuple for each call, so if you're worried about performance you should test it. In either case, you could pass in a precreated Func or Tuple to avoid the creation overhead.)
I have written the following method:
public static Dictionary<K, V> ListToDictionary<E, K, V>(
List<E> list, Func<E, K> keyProvider, Func<E, V> valueProvider)
{
Dictionary<K, V> dictionary = new Dictionary<K, V>();
foreach (E e in list)
{
K key = keyProvider(e);
V value = valueProvider(e);
dictionary.Add(key, value);
}
return dictionary;
}
This method takes in a list and transforms it into a dictionary using the given functions to extract keys and values from the list elements.
Now, to shorten things I have the following interface:
public interface IKeyValueProvider<K, V>
{
K GetKey();
V GetValue();
}
And an overload of the method mentioned above, looking like this:
public static Dictionary<K, V> ListToDictionary<E, K, V>(List<E> list) where E : IKeyValueProvider<K, V>
{
return ListToDictionary(list, x => x.GetKey(), x => x.GetValue());
}
I hoped that I could use this construction as follows:
Utils.ListToDictionary(someList)
Where someList is a List and E is a type (in my case, a struct) implementing IKeyValueProvider with concrete type parameters for K and V. But this does not seem to be possible since I get the error
The type arguments for method 'Dictionary Roadster.Other.Utils.ListToDictionary(List)' cannot be inferred from the usage.
Why is C# not able to infer the type arguments in such a scenario? Am I missing something obvious, which is the reason why they are not unique in this case, or is this simply not supported?
Edit: Sorry for the missing transparency of my "does not work" claim. Here is an example of how I try to use that functionality. I am a C# beginner, so maybe I am doing things fundamentally wrong.
So here is the example:
The struct, implementing IKeyValueProvider:
public struct A : IKeyValueProvider<string, string>
{
public string s1;
public string s2;
public string GetKey() => s1;
public string GetValue() => s2;
}
Usage of the method:
public void TestMethod()
{
A a1 = new A { s1 = "test", s2 = "banana" };
A a2 = new A { s1 = "serh", s2 = "weiougnw" };
List<A> aList = new List<A> { a1, a2 };
Dictionary<string, string> test = Utils.ListToDictionary(aList);
}
As I am assigning the result to a Dictionary explicitly, I would expect the arguments to be inferable here.
Is it possible to write an extension method that works only with dictionaries that have a List as value?
I want to write one that checks if the key is existent, it will add another entry to the list. And if the key is not existent a new list is initialized, the entry added, and then everything added to the dictionary.
Now I am not sure what the method head looks like or if it is even possible to limit the function to a specific value type.
Yes, of course. In the extension method defintition you use List<T>, which the T defined in the type arguments. In this case named TListValue to avoid ambiguity:
public static void DoSomething<TKey, TListValue>(this Dictionary<TKey, List<TListValue>> dictionary)
{
...
}
You can use it without specifying the type parameters. They should be infered:
Dictionary<string, List<string>> u = new Dictionary<string, List<string>>();
u.DoSomething();
Here is a sample implementation of the method that you want to write:
static class DictExtensions {
public static void Insert<TKey,TVal>(this IDictionary<TKey,List<TVal>> d, TKey k, TVal v) {
List<TVal> current;
if (!d.TryGetValue(k, out current)) {
d.Add(k, new List<TVal> { v } );
} else {
current.Add(v);
}
}
}
The name Add would collide with the instance method of Dictionary, so I used the name Insert.
Demo.
Rather than an extension method, I would personally create a class inheriting from Dictionary:
public class ListDictionary<TKey, TValue> : Dictionary<TKey, List<TValue>>
{
new public List<TValue> this[TKey index]
{
get
{
List<TValue> list = null;
if (!TryGetValue(index, out list))
{
list = new List<TValue>();
Add(index, list);
}
return list;
}
set
{
if (ContainsKey(index))
base[index] = value;
else
Add(index, value);
}
}
}
Usage:
ListDictionary<string, string> dictionary = new ListDictionary<string, string>();
dictionary["list1"].Add("item1"); // list will be initialised here
dictionary["list1"].Add("item2");
dictionary["list2"].Add("item1"); // and another
I have a class called IDCollection which is not actually a List<>, Dictionary<,>, or similar IEnumerable-based type. Though it does have an indexer, it's based on a private Dictionary<string, ID> called innerList, so objects of the class themselves are not lists, nor does it hold key value pairs or a collection of items through its own this accessor.
Is it possible to make an IDCollection object queryable in a LINQ expression? If so, how?
For example, suppose the object is called testIdColl. In that case...
from KeyValuePair<string, ID> k in testIDColl
select k;
etc.
And is the IQueryable interface involved at all?
This is all you would need to do to your class:
public class IDCollection : IEnumerable<KeyValuePair<string, ID>>
{
private IDictionary<string, ID> List = new Dictionary<string, ID>();
public IEnumerator<KeyValuePair<string, ID>> GetEnumerator()
{
return List.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
Then you could run this code:
var testIDColl = new IDCollection();
var query =
from KeyValuePair<string, ID> k in testIDColl
select k;
If you want you could make the entire IEnumerable<...> interface private like so:
public class IDCollection : IEnumerable<KeyValuePair<string, ID>>
{
private IDictionary<string, ID> List = new Dictionary<string, ID>();
IEnumerator<KeyValuePair<string, ID>> IEnumerable<KeyValuePair<string, ID>>.GetEnumerator()
{
return List.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return List.GetEnumerator();
}
}
Now nothing is directly exposed.
I created an implementation of the three instance methods from Jakub's answer:
public class IDCollection
{
private IDictionary<string, ID> List = new Dictionary<string, ID>() { { "x", new ID() }, } ;
public IEnumerable<KeyValuePair<string, ID>> Where(Func<KeyValuePair<string, ID>, bool> selector)
{
return List.Where(selector);
}
public IEnumerable<TResult> Select<TResult>(Func<KeyValuePair<string, ID>, TResult> selector)
{
return List.Select(selector);
}
}
The Cast method was not needed to perform basic queries.
I would suggest adding an explicit AsEnumerable() method instead to expose the full range of LINQ operators.
This would be the simplest and most robust way of doing queries:
public class IDCollection
{
private IDictionary<string, ID> List = new Dictionary<string, ID>() { { "x", new ID() }, } ;
public IEnumerable<KeyValuePair<string, ID>> AsEnumerable()
{
return List.Select(x => x);
}
}
The queries would have to look like:
var query =
from k in testIDColl.AsEnumerable()
where k.Key == "x"
select k;
The easiest solution is to implement IEnumerable<T>. It's only one method, which you can usually delegate to inner collection's GetEnumerator() or implement easily with yield return.
The name of your type (IDCollection) suggests that it should implement IEnumerable<T>, probably some other collection interface (e.g. ICollection<T>, IReadonlyCollection<T>).
If for some reason you don't want to use IEnumerable<T>, you can still make it work. First you need to understand how the compiler processes query expressions.
A LINQ query expression is first translated by the compiler to a series of method calls. For example the query expression
from KeyValuePair<string, int> item in collection
where item.Key == "abc"
select item.Value;
Is translated to
testIDColl
.Cast<KeyValuePair<string, int>>()
.Where(item => item.Key == "abc")
.Select(item => item.Value);
All you need to do to use a type as a source in a query expression is to make the above code compile. It means you will need Cast, Where, Select (and others too, like GroupBy, OrderBy) methods either as instance methods or extension methods.
For example the following class and extension methods will make the above query expression compile (although the methods don't do anything at all):
class IDCollection
{
}
static class IDCollectionExtensions
{
public static IDCollection Cast<TResult>(this IDCollection source)
{
return source;
}
public static IDCollection Where(this IDCollection source, Func<KeyValuePair<string, int>, bool> selector)
{
return source;
}
public static IDCollection Select<TResult>(this IDCollection source, Func<KeyValuePair<string, int>, TResult> selector)
{
return source;
}
}
Instance methods will work too:
class IDCollection
{
public IDCollection Cast<TResult>()
{
return this;
}
public IDCollection Where(Func<KeyValuePair<string, int>, bool> selector)
{
return this;
}
public IDCollection Select<TResult>(Func<KeyValuePair<string, int>, TResult> selector)
{
return this;
}
}
Rather than create a whole new class implementing ILookup<T> is it possible to add an extension method to dictionary which caters for it? I'm thinking something along the following:
public static void LookupAdd(this Dictionary<T, List<V>> dict, T key, V item)
{
if (!dict.ContainsKey(key))
{
dict.Add(key, new List<T>());
}
dict[key].Add(item);
}
This fails to compile saying it can't identify the types. I'm guessing that my generic parameters are too complex (particularly List<V>)
You have forgotten to add the generic parameter syntax:
public static void LookupAdd<T, V>(this Dictionary<T, List<V>> dictionary, T key, V item)
{
}
The <T, V> is missing.
Try...
public static void LookupAdd<T,V>(this Dictionary<T, List<V>> dict, T key, V item)
{
if (!dict.ContainsKey(key))
{
dict.Add(key, new List<V>());
}
dict[key].Add(item);
}
UPDATE:
Notice that you should have
new List<V>()
where you have
new List<T>()