I'm getting a "cannot convert from 'int' to 'TValue'" in the following code. How can I fix this? I understand why there is an issue, but I'm wonder the best way around this. Do I need to make a decision to specific type the ReturnValuesDict, and not leave it generic?
public class ReturnValuesDict<TKey, TValue> : CloneableDictionary<TKey, TValue>
{
public static ReturnValuesDict<TKey, TValue> CreateEmptyClone(ReturnValuesDict<TKey, TValue> current)
{
var newItem = new ReturnValuesDict<TKey, TValue>();
foreach (var curr in current)
{
newItem.Add(curr.Key, 0); // ERROR on the 2nd parameter here
}
return newItem;
}
}
The reason this does not compile is that 0 (an int) cannot, in general, be converted to the dictionary-values' type (TValue), which, as far as the compiler is concerned, is some arbitrary type. (where TValue : int wouldn't work, but that's another matter)
I assume you're trying to construct a dictionary with the same keys as the original, but with 'empty' values?
If you are ok with what .NET considers to be the 'default' value of a type, you could try changing the line to:
newItem.Add(curr.Key, default(TValue));
This will use the default-value of the dictionary-values' type. For example:null for reference-types, zero for numeric-value types.
If, on the other hand, the intention is to write a method that only works with dictionarys having intvalues, you could make it more restrictive (place this in another class):
public static ReturnValuesDict<TKey, int> CreateEmptyClone<TKey>(ReturnValuesDict<TKey, int> current)
{
var newItem = new ReturnValuesDict<TKey, int>();
foreach (var curr in current)
{
newItem.Add(curr.Key, 0);
}
return newItem;
}
Note that the method is now a generic method that takes an unconstrained genericTKeyparameter.
Related
Recently, I have found out that indexer can accept an array of arguments as params:
public class SuperDictionary<TKey, TValue>
{
public Dictionary<TKey, TValue> Dict { get; } = new Dictionary<TKey, TValue>();
public IEnumerable<TValue> this[params TKey[] keys]
{
get { return keys.Select(key => Dict[key]); }
}
}
Then, you will be able to do:
var sd = new SuperDictionary<string, object>();
/* Add values */
var res = sd["a", "b"];
However, I never met such usage in .NET Framework or any third-party libraries. Why has it been implemented? What is the practical usage of being able to introduce params indexer?
The answer has been found in a minute after posting the question and looking through the code and documentation - C# allows you to use any type as a parameter for indexer, but not params as a special case.
According to MSDN,
Indexers do not have to be indexed by an integer value; it is up to you how to define the specific look-up mechanism.
In other words, indexer can be of any type. It can either be an array...
public IEnumerable<TValue> this[TKey[] keys]
{
get { return keys.Select(key => Dict[key]); }
}
var res = sd[new [] {"a", "b"}];
or any kind of another unusual type or collection, including params array, if it seems to be convenient and suitable in your case.
How can I get the key values of a generic IDictionary<,> using reflection.
This is the type of thing I want to do.
public static string Format<T>(T item)
{
if (item.GetType().GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>)))
{
// I know it's a IDictionary so figure out what the types are
Type keyType = item.GetType().GetGenericArguments()[0];
Type valueType = item.GetType().GetGenericArguments()[1];
//Now cast it to the correct IDictionary. How do I properly inject the type here?
var keyList = ((IDictionary<keyType, valueType>)item).Select(x => x.Key.ToString()).ToArray<string>();
}
}
Edit: Clarified that I want to use reflection
I think you are overcomplicating things. When I look at your code, you are trying to do the following:
myDictionary.Keys.Select(k => k.ToString()).ToArray();
So,
public string Format<T>(T value) {
if (##item is dictionary) {
var items = name.GetType().GetProperty("Keys", BindingFlags.Instance | BindingFlags.Public).GetValue(item) as IEnumerable;
if (items == null) throw new ArgumentException("Dictionary with no keys?");
string[] data = items.OfType<object>().Select(o => o.ToString()).ToArray();
}
}
Unfortunately you cannot pass a System.Type as a type argument. If you want to use the IDictionary<,> properties, you need to do a little more reflection.
var dictionaryType = typeof(IDictionary<,>).MakeGenericType(keyType, valueType);
var keysProperty = dictionaryType.GetProperty("Keys");
var keys = ((IEnumerable)keysProperty.GetValue(item)).OfType<object>().Select(k => k.ToString()).ToArray<string>();
However, if all you want are the keys, you can just use the non-generic IDictionary interface, and don't bother with reflection.
var dictionary = item as IDictionary;
if (dictionary != null)
{
var keyList = dictionary.Select(x => x.Key.ToString()).ToArray<string>();
}
You got a few problems here. One minor issue is you don't use the found interface for getting the generic arguments.
The other bigger problem is you're trying to use dynamically found types in types defined statically at compile time (IDictionary<keyType, valueType>).
If you want to continue down this road it's using reflection, which can be hard. Depending on your goal you could choose another path and try this out:
public static string Format<TKey,TValue>(IDictionary<TKey,TValue> item)
{
var keyList = item.Select(x => x.Key.ToString()).ToArray();
// do some work with keyList and return a string.
}
This will still work public static string Format<T>(T item) handling other types, so implementing this beside it:
public static string Format<T>(T item)
{
// handle non IDictionary<,> objects here
}
Making you able to call format anywhere:
Format(new Dictionary<string,int> { { "hello world", 1337 } });
Format("string");
Format(new { Hello = "World" });
The issue is that you're trying to get generic code parameters from Type objects. This is not directly possible, because Type is a class like nay other, it just represents a class, and type arguments are used to compile the method. Thus, you can't get new type arguments within the underlying code...
That being said, You could add extra generic parameters, with specific constraints,
public static Format<T, TKey, TValue>(T item)
where T : IDictionary<TKey, TValue>
Or, to be more succinct
public static Format<TKey, TValue>(IDicitonary<TKey, TValue> item)
This can then be called using dynamic so as to ensure the proper arguments are used
public static string Format<T>(T item)
{
if (item.GetType().GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>)))
{ FormatDictionary((dynamic) item); }
}
private static FormatDictionary<TKey, TValue>(IDicitonary<TKey, TValue> item)
If you must perform these calls with Type objects, you'll have do so via metacode - either with more reflection calls, or by compiling a method using Expressions
In this thread
How to get null instead of the KeyNotFoundException accessing Dictionary value by key?
in my own answer I used explicit interface implementation to change the basic dictionary indexer behaviour not to throw KeyNotFoundException if the key was not present in the dictionary (since it was convinient for me to obtain null in such a case right inline).
Here it is:
public interface INullValueDictionary<T, U>
where U : class
{
U this[T key] { get; }
}
public class NullValueDictionary<T, U> : Dictionary<T, U>, INullValueDictionary<T, U>
where U : class
{
U INullValueDictionary<T, U>.this[T key]
{
get
{
if (ContainsKey(key))
return this[key];
else
return null;
}
}
}
Since in a real application I had a list of dictionaries, I needed a way to access the dictionaries from the collection as an interface. I used simple int indexer to acess each element of the list.
var list = new List<NullValueDictionary<string, string>>();
int index = 0;
//...
list[index]["somekey"] = "somevalue";
The easiest thing was to do something like this:
var idict = (INullValueDictionary<string, string>)list[index];
string value = idict["somekey"];
The question raised when I decided to try to use covariance feature to have a collection of interfaces to use instead. So I needed an interface with covariant type parameter for the cast to work. The 1st thing that came to my mind was IEnumerable<T>, so the code would look like this:
IEnumerable<INullValueDictionary<string, string>> ilist = list;
string value = ilist.ElementAt(index)["somekey"];
Not that nice at all, besides ElementAt instead of an indexer is way worse.
The indexer for List<T> is defined in IList<T>, and T there is not covariant.
What was I to do? I decided to write my own:
public interface IIndexedEnumerable<out T>
{
T this[int index] { get; }
}
public class ExtendedList<T> : List<T>, IIndexedEnumerable<T>
{
}
Well, few lines of code (I don't even need to write anything in ExtendedList<T>), and it works as I wanted:
var elist = new ExtendedList<NullValueDictionary<string, string>>();
IIndexedEnumerable<INullValueDictionary<string, string>> ielist = elist;
int index = 0;
//...
elist[index]["somekey"] = "somevalue";
string value = ielist[index]["somekey"];
Finally the question: can this covariant cast be somehow achieved without creating an extra collection?
You can try use IReadOnlyList<T>, which is implemented by List<T>.
Note that I've added one instance of NullValueDictionary<string, string> to List, so that you won't get ArgumentOutOfRangeException at elist[index] line.
IReadOnlyList<NullValueDictionary<string, string>> elist = new List<NullValueDictionary<string, string>>
{
new NullValueDictionary<string, string>()
};
IReadOnlyList<INullValueDictionary<string, string>> ielist = elist;
int index = 0;
//...
elist[index]["somekey"] = "somevalue";
string value = elist[index]["somekey"];
Edit: I've searched for covariant interfaces and collections with indexes prior to .NET 4.5, but found none. Still I think there are a little bit easier solution, than to create separate interface - just to cast one collection to another.
List<INullValueDictionary<string, string>> ielist = elist.Cast<INullValueDictionary<string, string>>().ToList();
Or use covariance gained from arrays
INullValueDictionary<string, string>[] ielist = elist.ToArray()
LINQ has some optimization that work on whole type compatibility, so you won't iterate over sequence if those types are compatible.
Cast implementation taken from MONO Linq
public static IEnumerable<TResult> Cast<TResult> (this IEnumerable source)
{
var actual = source as IEnumerable<TResult>;
if (actual != null)
return actual;
return CreateCastIterator<TResult> (source);
}
Note that I have changed INullValueDictionary<T, U> interface to contain set in the property so that ielist[index]["somekey"] = "somevalue"; will work.
public interface INullValueDictionary<T, U> where U : class
{
U this[T key] { get; set; }
}
But again - if creating a new Interface and class is ok for you and you don't want to mess around with casts everywhere - I think it is a good solution, if you have considered at the constraints, it gives.
In search of covariance in mscorlib
This probably won't be interesting to you, but I've just wanted to find out what Types are covariant in mscorlib assembly. By running next script I received only 17 types are covariant, 9 of which are Funcs. I have omitted IsCovariant implementation, because this answer is too long even without it
typeof(int).Assembly.GetTypes()
.Where(type => type.IsGenericType)
.Where(type=>type.GetGenericArguments().Any(IsCovariant))
.Select(type => type.Name)
.Dump();
//Converter`2
//IEnumerator`1
//IEnumerable`1
//IReadOnlyCollection`1
//IReadOnlyList`1
//IObservable`1
//Indexer_Get_Delegate`1
//GetEnumerator_Delegate`1
I am working in the .NET 2.0 framework. I have some code working, just want it working a little more elegantly.
I have a need to effectively "mirror" a Dictionary object such that if we start with an object like this
Dictionary<TKey,TValue> StartDictionary;
We can Mirror it like this
Dictionary<TValue,TKey> MirroredDictionary = MirrorDictionary(StartDictionary);
And we would end up with a new dictionary with the values and keys being swapped for each KeyValuePair
Before anyone asks me why: the source dictionary is fairly large and loaded once from reflection calls when my program loads. I don't want to run the same reflection calls a second time to load the mirrored dictionary. Creating a mirrored Dictionary and populating its values and keys the way I came up with seemed to me to be much less costly.
So being the kind of person that hates to rewrite things, I decided to write a Generic method in a helper class I have to do the Mirror using Generics.
Now mind you I've written simple Generic methods before for normal scalar types
Here's what I came up with
public static TOutDic MirrorDictionary<TInDic, TOutDic>(TInDic InDictionary)
where TInDic : IDictionary
where TOutDic : IDictionary
{
Type[] KVPTypes = typeof(TInDic).GetGenericArguments();
Type TKey = KVPTypes[0];
Type TValue = KVPTypes[1];
Type TDic = typeof(Dictionary<,>).MakeGenericType(TValue, TKey);
IDictionary OutDic = (IDictionary)Activator.CreateInstance(TDic);
foreach (DictionaryEntry DE in (IDictionary)InDictionary) OutDic.Add(DE.Value, DE.Key);
return (TOutDic)OutDic;
}
A little bit there but it works, Loads up the Types of the Keys and Values and creates an instance of the mirrored Dictionary
Then just looping through the base DictionaryEntries of the InDictionary it adds the items to the OutDic and returns it casting it to the Type expected
Compiles just fine
Now when i go to call it I would think just like when i call a Generic method for a scalar type I could just using our code snippits above say
Dictionary<TValue,TKey> MirroredDictionary = MirrorDictionary(StartDictionary);
But that does not compile gives me
The type arguments for method MirrorDictionary(TInDic)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
So If I call it instead like this
Dictionary<TValue, TKey> MirrorDic = MirrorDictionary<Dictionary<Tkey, TValue>, Dictionary<TValue,TKey>>(StringDic);
It compiles and works like a charm.
Now the question becomes how do I make it properly infer the Type being passed into this method when the Type being passed in and the Type being passed out are complex types like in this example?
You can make life much easier for the compiler by telling it the key and value types thus:
public static Dictionary<TValue, TKey> MirrorDictionary<TKey, TValue>
(Dictionary<TKey, TValue> source)
{
Dictionary<TValue, TKey> destination = new Dictionary<TValue, TKey>();
foreach (KeyValuePair<TKey, TValue> kvp in source)
{
destination.Add(kvp.Value, kvp.Key);
}
return destination;
}
I don't think you need reflection here at all.
Sample usage:
static void Main(string[] args)
{
Dictionary<int, string> source = new Dictionary<int, string>();
source.Add(3, "foo");
source.Add(4, "bar");
DumpDic(source);
DumpDic(MirrorDictionary(source));
Console.ReadLine();
}
where DumpDic is:
public static void DumpDic<TK, TV>(Dictionary<TK, TV> dic)
{
foreach (KeyValuePair<TK, TV> keyValuePair in dic)
{
Console.WriteLine("{0} => {1}", keyValuePair.Key, keyValuePair.Value);
}
}
Here's a 3.5 solution (you can also use it in 2.0 with VS2008 and LinqBridge)
IDictionary<TValue, TKey> MirrorDictionary<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
return dict.ToDictionary(kvp => kvp.Value, kvp => kvp.Key);
}
And a pure 2.0 solution
IDictionary<TValue, TKey> MirrorDictionary<TKey, TValue>(IDictionary<TKey, TValue> dict)
{
Dictionary<TValue, TKey> newDict = new Dictionary<TValue, TKey>();
foreach(KeyValuePair<TKey, TValue> kvp in dict)
{
newDict.Add(kvp.Value, kvp.Key);
}
return newDict;
}
Type inference should work fine with both solutions (as they have the same signature)
You could define the Out dictionary as an out parameter. Type inference does not look the type of the variable you're assigning to, only the types of the parameters. That's the reason this doesn't compile.
You need to tell it what TValue and TKey are. Unless they are defined up in the signature of the method calling this code, they don't have any specific types. You need to give it something like:
Dictionary<string, int> MirroredDictionary = MirrorDictionary(StartDictionary);
I am building the following class to manage a dictionary.
public class EnumDictionary<TKey, TValue>
{
private Dictionary<TKey, TValue> _Dict;
public EnumDictionary(Dictionary<TKey, TValue> Dict)
{
this._Dict = Dict;
}
public TKey GetValue(TValue value)
{
foreach (KeyValuePair<TKey, TValue> kvp in _Dict)
{
if (kvp.Value == value)
return kvp.Key;
}
throw new Exception("Undefined data type: " + value);
}
}
But I am getting an error "Operator '==' cannot be applied to operands of type 'TValue' and 'TValue'".
BTW, I am making this custom collection is because my dictionary has unique value, but I can't get key by value from a dictionary.
Any help is appreciated. Thank you.
Did you try using the Equals method?
if (kvp.Value.Equals(value))
I think this restriction is due to the fact that the == operator can't be used with all types. Take the following for instance:
struct Test
{
public int Value;
}
Given the above struct, the following code will not compile:
Test a, b;
a = b = new Test();
bool areEqual = a == b; // Operator '==' cannot be applied to
// operands of type 'Test' and 'Test'
However, all types have the Equals method, so calling that will work:
Test a, b;
a = b = new Test();
bool areEqual = a.Equals(b);
Fredrik is right; you need to use Equals as you can't presume to be able to use == for all types, since the operator isn't defined for every type.
Depending on your scenario, it might also make sense to add
where TValue : IEquatable<TValue>
as a generic type constraint on your class. The reason for this is that object.Equals accepts another object as a parameter, which means that if TValue is a value type it will be boxed. If it can be known to implement IEquatable<TValue>, on the other hand, then Equals can be resolved to IEquatable<TValue>.Equals*, which takes a TValue as a parameter and therefore won't require value types to be boxed.
I might also recommend that you rethink the internal structure of this class. As it currently stands, there's no reason you need this class at all, as you could easily add an extension method to IDictionary<TKey, TValue> to find a key by value via enumeration over the values. What I would do instead is store two dictionaries: a Dictionary<TKey, TValue> and a Dictionary<TValue, TKey>, so that two-way lookup is possible in O(1).
*By the way, in case you're curious, the reason you can't use IEquatable<T> (or any interface for that matter) to ensure that a type has implemented the == operator is that operators are static, and interfaces cannot provide static methods (and thus can't provide operators).
When you use generic comparsions I think you should implement a (x)CompareTo(Y) or a comparable class. Please correct me if im wrong.
you can use if (kvp.Value.Equals(value)) instead of ==.
Use the "where" condition on your generic types
class Dictionary<TKey,TVal>
where TKey: IComparable, IEnumerable
where TVal: MyI
{
public void Add(TKey key, TVal val)
{
}
}
from http://msdn.microsoft.com/en-us/library/6b0scde8%28VS.80%29.aspx
Don't create a new class. Create a extension method:
public static class DictionaryHelper
{
public static TKey GetKeyFromValue<TKey, TValue>(this IDictionary<TKey, TValue> instance, TValue value)
{
foreach (var kvp in instance)
{
if (kvp.Value.Equals(value))
return kvp.Key;
}
return default(TKey);
}
}
public class Example
{
public static void Main(string[] argv)
{
Dictionary<string, string> test = new Dictionary<string, string> { { "Mykey", "MyValue" }, { "Key1", "Value2" } };
string key = test.GetKeyFromValue("MyValue");
}
}
If you want this to be general purpose, then you will want the definition of equality to be configurable, just as it is in the dictionary for keys.
Have a property of type IEqualityComparer<TValue>, which is set in the constructor.
Then have a version of the constructor that makes the default EqualityComparer<TValue>.Default. This will work by calling Equals on the type in question.
public class EnumDictionary<TKey, TValue>
{
private Dictionary<TKey, TValue> _Dict;
private readonly IEqualityComparer<TValue> _cmp;
public EnumDictionary(Dictionary<TKey, TValue> Dict, IEqualityComparer<TValue> cmp)
{
this._Dict = Dict;
_cmp = cmp;
}
public EnumDictionary(Dictionary<TKey, TValue> Dict)
:this(Dict, IEqualityComparer<TValue>.Default){}
public TKey GetValue(TValue value)
{
foreach (KeyValuePair<TKey, TValue> kvp in _Dict)
{
if (cmp.Equals(kvp.Value, value))
return kvp.Key;
}
throw new Exception("Undefined data type: " + value);
}
}