public class Flea : Animals {...}
var fleas = new Dictionary<int, Flea>();
public IReadOnlyDictionary<string, Animal> Animals => fleas.ToDictionary(pair => pair.Key, pair => (Animal)pair.Value);
Q Is there a more efficient way to obtain Animals from fleas?
.NET supports covariance in interfaces, delegates, generic types and arrays. The interface or type has to specify it's covariant though with the out keyword.
You can write
IEnumerable<Animal> animals=new List<Flea>();
or
var dict=new Dictionary<int,Flea>{
[1]=new Flea()
};
IEnumerable<Animal> animals=dict.Values;
This works because Dictionary.Values returns an IEnumerable<Flea> and IEnumerable is covariant - its definition is IEnumerable<out T>.
KeyValuePair though isn't covariant which means that the classes that use it like IDictionary<TKey,TValue> and IReadOnlyDictionary<TKey,TValue> aren't either. This was intentional.
Since you only need to read from that dictionary, you can create an accessor method using a delegate or, in C# 7 and later, a local function. You can pass that function to methods that expect a Func<TKey,TValue> and use it to read values from the dictionary.
If you have a method that needs key-based access, let's say :
void Process(Func<int,Animal> reader)
{
var value=reader(1);
}
In C# 7 you can write :
var dict =...
Animal get(int key)=>dict[key];
Process(get);
This cheats a bit, by using variable capture to access the dictionary.
Before C# 7 you'd use a delegate :
Func<int,Animal> get= key=>dict[key];
Process(get);
This may seem strange, but that's how LINQ itself works, by using predicates and delegates instead of interfaces and wrappers.
The .NET framework does not contain a dictionary wrapper that supports upcasting, but implementing one is trivial:
public class ReadOnlyDictionaryUpcast<TKey, TValueDerived, TValueBase>
: IReadOnlyDictionary<TKey, TValueBase> where TValueDerived : TValueBase
{
private readonly Dictionary<TKey, TValueDerived> _dictionary;
public ReadOnlyDictionaryUpcast(Dictionary<TKey, TValueDerived> dictionary)
{
_dictionary = dictionary;
}
public int Count => _dictionary.Count;
public TValueBase this[TKey key] => _dictionary[key];
public bool ContainsKey(TKey key) => _dictionary.ContainsKey(key);
public bool TryGetValue(TKey key, out TValueBase value)
{
bool result = _dictionary.TryGetValue(key, out TValueDerived valueDerived);
value = valueDerived;
return result;
}
public IEnumerator<KeyValuePair<TKey, TValueBase>> GetEnumerator() => _dictionary
.Select(e => new KeyValuePair<TKey, TValueBase>(e.Key, e.Value))
.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerable<TKey> Keys => _dictionary.Keys;
public IEnumerable<TValueBase> Values =>
(IEnumerable<TValueBase>)(IEnumerable<TValueDerived>)_dictionary.Values;
}
Usage example:
var animals = new ReadOnlyDictionaryUpcast<string, Flea, Animal>(fleas);
Related
I am trying to create a for loop that invokes a function of several instance of class A in a dictionary, and if there is no value for a key, it creates it and then invokes it.
It seems to me as if there must be a way to create a value upon first access to a key.
I am currently using this code though I think it is not the best possible practice:
(dictionary[i] = dictionary.ContainsKey(arr[i]) ? dictionary[i] : new A()).Push(10);
Is there a cleaner for such a problem in C#?
ConcurrentDictionary has a GetOrAdd method (and other useful methods like AddOrUpdate, TryRemove etc.). If just a plain dictionary had GetOrAdd you could use that...
Luckily, you can create an extension method in a static class which you probably should name DictionaryExtensions:
public static TValue GetOrAdd<TKey, TValue>(
this IDictionary<TKey, TValue> dictionary,
TKey key,
Func<TKey, TValue> valueFactory)
{
if (dictionary == null)
throw new ArgumentNullException(nameof(dictionary));
if (key == null)
throw new ArgumentNullException(nameof(key));
if (valueFactory == null)
throw new ArgumentNullException(nameof(valueFactory));
if (dictionary.TryGetValue(key, out var existingValue))
return existingValue;
var value = valueFactory(key);
dictionary.Add(key, value);
return value;
}
How to use it:
dictionary.GetOrAdd(i, () => new A()).Push(10);
This version uses a value factory so that new A() is only executed in case it is required. Another ConcurrentDictionary.GetOrAdd() overload uses a value provided as parameter which you might consider as an alternative.
I find that creating extension methods like this that closely mirrors the methods on ConcurrentDictionary is very useful.
I'd say a cleaner code would look something like this:
var key = arr[i];
var hasKey = dictionary.ContainsKey(key);
if (!hasKey)
dictionary.Add(key, new A());
var itemToUse = dictionary[key];
itemToUse.Push(10);
Although it seems to me you are looking for something shorter. I guess what you are really asking is a short-hand method that does:
Returns the value for a given key if the key exists, else adds the key to the dictionary with some default value.
I think the above code tells a lot more about the intent, but in case you want something different, I can think of following two solutions.
The first one is an extension method for getting the item:
public static TValue Get<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue)
{
var hasKey = dictionary.ContainsKey(key);
if (!hasKey)
dictionary.Add(key, defaultValue);
return dictionary[key];
}
You would use it as:
dict.Get(arr[i], defaultValue: new A())
.Push(10);
The second solution I can think of is a new derivative of Dictionary:
class DefaultDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
private readonly Func<TKey, TValue> _defaultValueFactory;
public DefaultDictionary(TValue defaultValue)
{
_defaultValueFactory = new Func<TKey, TValue>(x => defaultValue);
}
public DefaultDictionary(Func<TValue> defaultValueFactory)
{
_defaultValueFactory = new Func<TKey, TValue>(x => defaultValueFactory()) ?? throw new ArgumentNullException(nameof(defaultValueFactory));
}
public DefaultDictionary(Func<TKey, TValue> defaultValueFactory)
{
_defaultValueFactory = defaultValueFactory ?? throw new ArgumentNullException(nameof(defaultValueFactory));
}
public new TValue this[TKey key]
{
get
{
var hasKey = ContainsKey(key);
if (!hasKey)
{
var defaultValue = _defaultValueFactory(key);
Add(key, defaultValue);
}
return base[key];
}
set
{
base[key] = value;
}
}
}
The usage of this goes like:
var dictionary = new DefaultDictionary<string, A>(() => new A());
// ...
dictionary[arr[i]].Push(10);
I must warn you about something, this derivative of Dictionary hides the index operator. And since using IDictionary as types for members is a common practice (e.g. private IDictionary<string, A> dictionary as a member), you can't use the overloaded version without casting. So either cast your variable to DefaultDictionary every time you want to use the overloaded indexer, or have an interface for this new dictionary like:
interface IDefaultDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
new TValue this[TKey key] { get; set; }
}
And have your members, variables use it as their defining type:
private IDefaultDictionary<string, A> dictionary;
But this also means as a concrete class you must now use DefaultDictionary, and that's the trade-off.
I want to write a method which return all key value pairs containing in a IDictionary as Map.EntrySet() does in java.
I tried as:
For example we define IDictionary as:
private IDictionary<T, MutableInt> _map = new Dictionary<T, MutableInt>();
The method as:
public KeyValuePair<T, MutableInt> KeyValuePairSet()
{
return KeyValuePair<T, MutableInt>(_map.Keys, _map.Values);
}
while returning statement, the error raised is:
KeyValuePair<T, MutableInt> is a type but used like a variable
How can this method be implemented?
Actually it is fairly easily, because IDictionary<TKey, TValue> implmentents the interface IEnumerable<KeyValuePair<TKey, TValue>> all you need to do is declare your HashSet and pass the dictionary in because HashSet<T> has a constructor that takes in a IEnumerable<T> as its parameter.
public ISet<KeyValuePair<T, MutableInt>> KeyValuePairSet()
{
return new HashSet<KeyValuePair<T, MutableInt>>(_map);
}
Given:
private IDictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
If you want to return IEnumerable of KeyValuePairs:
IEnumerable<KeyValuePair<T, MutableInt>> get_pairs()
{
return map;
}
If you want to return KeyValuePair of keys and values of map:
KeyValuePair<IEnumerable<T>, IEnumerable<MutableInt>> get_pair()
{
return new KeyValuePair<IEnumerable<T>, IEnumerable<MutableInt>>(map.Keys, map.Values);
}
If you want to return HashSet of KeyValuePairs:
ISet<KeyValuePair<T, MutableInt>> get_pairs()
{
return new HashSet<KeyValuePair<T, MutableInt>>(map);
}
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;
}
}
I have a generic dictionary that pass to a method which only accepts IQueryable as a parameter
Is it possible to cast the queryable back to the original dictionary? And I don't mean creating a new dictionary with .ToDictionary(...)
private static void Main()
{
var dict = new Dictionary<int, int>();
dict.Add(1,1);
SomeMethod(dict.AsQueryable());
}
public static void SomeMethod(IQueryable dataSource)
{
// dataSource as Dictionary<int, int> --> null
var dict = dataSource.???
}
I know in this simple example this does not make much sense. But in the big picture I have an interface which requires me to return an IQueryable as a dataSource. On implementation returns a dictionary. On a different place in my code I have classes that process the dataSources.
The processor knows that the dataSource will be an Dictionary but I don't want to have the overhead for creating another Dictionary if I already have one.
The .AsQueryable() extension method returns an instance of the EnumerableQuery<T> wrapper class if it is called on something that was not already an IQueryable<T>.
This wrapper class has an .Enumerable property with internal access that provides access to the original object that .AsQueryable() was called on. So you could do this to get back your original dictionary:
var dict = new Dictionary<int, int>();
dict.Add(1,1);
var q = dict.AsQueryable();
Type tInfo = q.GetType();
PropertyInfo pInfo = tInfo.GetProperties(BindingFlags.NonPublic |
BindingFlags.Instance)
.FirstOrDefault(p => p.Name == "Enumerable");
if (pInfo != null)
{
object originalDictionary = pInfo.GetValue(q, null);
Console.WriteLine(dict == originalDictionary); // true
}
However, this is generally a pretty bad idea. internal members have their access restricted for a reason, and I don't think there's any guarantee that the internal implementation of .AsQueryable() won't change at some point in the future. So your best bet is to either find a way to make the original dictionary accessible, or go ahead and make a new one.
One possible workaround (which is not great) is to make your own wrapper class to carry the dictionary along:
private class DictionaryQueryHolder<TKey, TValue> : IQueryable<KeyValuePair<TKey, TValue>>
{
public IDictionary<TKey, TValue> Dictionary { get; private set; }
private IQueryable<KeyValuePair<TKey, TValue>> Queryable { get; set; }
internal DictionaryQueryHolder(IDictionary<TKey, TValue> dictionary)
{
Dictionary = dictionary;
Queryable = dictionary.AsQueryable();
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return Queryable.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Expression Expression
{
get { return Queryable.Expression; }
}
public Type ElementType
{
get { return Queryable.ElementType; }
}
public IQueryProvider Provider
{
get { return Queryable.Provider; }
}
}
This would both act as a wrapper for the dictionary's IQueryable<T> and provide access to the original dictionary. But on the other hand, anyone trying to retrieve the dictionary would have to know what the generic type parameters were (e.g. <string, string>, <int, string>, etc.) in order to cast it successfully.
The main problem here is that IQueryable wraps itself around the Dictionary rather than being like IEnumerable<> over IDictionary<>, where you could cast it back.
You can certainly find out if the type wrapped is a dictionary if you know the types involved:
public bool isDictionary<T>(object obj) {
return obj.GetType().GenericTypeArguments.Contains(typeof(T));
}
isDictionary<KeyValuePair<string,string>>(dataSource);
If you don't mind reaching into the objects internals, you could use the private Enumerable field on EnumerableQuery to get a version of (possibly) the original dictionary back as an IEnumerable<>
But to actually convert from an EnumerableQuery<KeyValuePair<int,int>> hiding under an IQueryable without doing that I think you'd have to just take the hit and create a new dictionary from it.
I have the following code
public class TestAdaptor
{
private interface ITargetClass
{
Guid Id { get; }
string Name { get; }
}
private class MyTargetClass : ITargetClass
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public MyTargetClass(MySourceClass source)
{
}
}
private class MySourceClass
{
public Guid Id { get; set; }
public string Name { get; set; }
}
private Dictionary<Guid, IEnumerable<ITargetClass>> ConvertItems(Dictionary<Guid, IEnumerable<MySourceClass>> source)
{
return source.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Select(v => new MyTargetClass(v)));
}
}
However this will not compile as the ToDictionary line causes the following error
Cannot implicitly convert type
'System.Collections.Generic.Dictionary<System.Guid,System.Collections.Generic.IEnumerable<TestAdaptor.TestAdaptor.MyTargetClass>>'
to
'System.Collections.Generic.Dictionary<System.Guid,System.Collections.Generic.IEnumerable<TestAdaptor.TestAdaptor.ITargetClass>>' ...\TestAdaptor.cs 38 20
Now it is clearly obvious that MyTargetClass implements ITargetClass but the compiler doesn't pick this up.
For now I am explicitly converting (ITargetClass)new MyTargetClass(v)
But why is this happening in the first place and is there a better way to resolve this?
The compiler wont automatically convert IEnumberable<X> to IEnumerable<Y> even if X : Y because IDictionary is not covariant. The rationale for this is discussed here: IDictionary<,> contravariance? and IDictionary<TKey, TValue> in .NET 4 not covariant
As for getting around it, like you mentioned, you'll have to cast:
With Cast extension method:
kvp => kvp.Value.Select(v => new MyTargetClass(v)).Cast<ITargetClass>()
Explicit cast:
kvp => kvp.Value.Select(v => (ITargetClass) new MyTargetClass(v))
Update:
Just to expand on this because of the confusion between IEnumerable and IDictionary. IEnumerable is covariant. IDictionary is not.
This is just fine:
IEnumerable<ITargetClass> list = new List<MyTargetClass>();
This is not:
IDictionary<object, IEnumerable<ITargetClass>> dict =
new Dictionary<object, List<MyTargetClass>>();
IDictionary inherits from IEnumerable<KeyValuePair<TKey, TValue>>. At issue is the KeyValuePair which is not covariant, which makes IDictionary not covariant.
Select only reports what is being created and not a facet of the objects type. Let the select know what you are using via the as keyword.
Select(v => new MyTargetClass(v) as ITargetClass));
It is not the compiler's job to understand an intention of a developer, for a class may express many interfaces. One has to provide hints to the select statement which ultimately brings it in line with the return object required.
Otherwise you can filter the elements and return an IEnumerable of the interface using OfType IEnumerable extension to return what is required by your method.
.Select(v => new MyTargetClass(v))
.OfType<ITargetClass>()