Reputation: 5226
I have this method
public string DictionaryToString<T, U>(Dictionary<T, U> dict)
{
var valueStrings = dict.Select(x => x.Key.ToString() + ": " + x.Value.ToString());
return String.Join("\n", valueStrings);
}
And I have this object that I want to pass into it
if ((value !=null) && value.GetType().IsGenericType &&
value.GetType().GetGenericTypeDefinition() == typeof (Dictionary<,>))
{
var castValue = value as Dictionary<,>; // this cast does not work
return DictionaryToString(castValue);
}
else
{
return value.ToString();
}
I can use reflection code like this in .Net 4.5
var targetMethodInfo = typeof(MyType).GetMethod("DictionaryToString");
var valueTypeArgs = value.GetType().GenericTypeArguments;
var genericMethod = targetMethodInfo.MakeGenericMethod(valueTypeArgs);
var result = genericMethod.Invoke(this, new[] {value });
return result.ToString();
ButType.GenericTypeArguments
is new in .Net 4.5. So how can I do that cast in .Net 4.0?
Upvotes: 0
Views: 896
Reputation: 64487
You are only calling ToString
on the key and value, so simply have this method take an IDictionary
(non-generic), you are not using anything in there that is type-specific to T
or U
.
You can then simply cast all arguments to IDictionary
:
var d = arg as IDictionary;
if (d != null)
{
var res = DictionaryToString(d);
}
You may also need to amend the DictionaryToString
implementation:
static string DictionaryToString(IDictionary d)
{
var vals = new List<string>();
foreach (DictionaryEntry de in d)
{
vals.Add(de.Key.ToString() + ": " + de.Value.ToString());
}
return String.Join("\n", vals);
}
Alternatively, if you really want to use LINQ, you could try casting to dynamic
(it isn't possible to cast to anything else as this could be a generic dictionary (KeyValuePair<>
) or non-generic hashtable (DictionaryEntry
)):
var valueStrings = d.Cast<dynamic>().Select(de => de.Key.ToString() + ": " + de.Value.ToString());
return string.Join("\n", valueStrings);
This basically "duck types" the existence of the Key
and Value
properties.
Upvotes: 3
Reputation: 17584
This sounds like it might be a case for the old System.Collections
namespace:
private static string DictionaryToString(IDictionary dict) {
if (null == dict) throw new ArgumentNullException("dict");
var valueStrings = new List<string>();
foreach (DictionaryEntry item in dict) {
valueStrings.Add(item.Key + ": " + item.Value);
}
return string.Join("\n", valueStrings.ToArray());
}
private static string Test(object value) {
var dict = value as IDictionary;
if (dict != null) {
return DictionaryToString(dict);
}
if (value == null) {
return null;
}
return value.ToString();
}
private static void Main(string[] args) {
var aDictionary = new Dictionary<int, string> {
{ 1, "one" },
{ 2, "two" },
{ 3, "three" }
};
Console.WriteLine(Test(aDictionary));
var anotherDictionary = new Dictionary<string, object> {
{ "one", 1 },
{ "two", "2" },
{ "three", new object() }
};
Console.WriteLine(Test(anotherDictionary));
Console.ReadLine();
}
Reasoning:
The non-generic IDictionary
will be a collection of key-value pairs in which the key is an object
and the value is an object
. All instances of object
support ToString
, so all keys and values of the collection can be converted to a string
without knowing their specific types.
The reason why this does not work:
var castValue = value as Dictionary<,>
is because the generic type Dictionary<TKey, TValue>
requires 2 type arguments. Without those type arguments, the collection is not generic. You'd be better off using the non-generic IDictionary
if you do not know the key or value types at compile-time.
Upvotes: 1
Reputation: 33381
Why not?
if ((value !=null) && value.GetType().IsGenericType &&
value.GetType().GetGenericTypeDefinition() == typeof (Dictionary<,>))
{
return DictionaryToString(castValue);
}
else
{
return value.ToString();
}
Upvotes: 0
Reputation: 54887
You could cast to dynamic
in .NET 4.0. The prior typeof(Dictionary<,>)
check will ensure that you won't get runtime errors.
var castValue = value as dynamic;
return DictionaryToString(castValue);
Upvotes: 0
Reputation: 3013
GetGenericTypeDefinition is available for previous versions http://msdn.microsoft.com/en-us/library/system.type.getgenerictypedefinition(v=vs.100).aspx. I think the 4.5 page on MSDN is missing the "Other versions" dropdown.
Upvotes: 0