使用未知类型的对象调用泛型方法

时间:2012-12-12 13:27:39

标签: c# generics casting

我有这个方法

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);
}

我有这个对象,我想传递给它

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();
}

我可以在.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();

Type.GenericTypeArguments是.Net 4.5中的新功能。那么如何在.Net 4.0中进行演员表演?

5 个答案:

答案 0 :(得分:3)

你只是在密钥和值上调用ToString,所以只需让这个方法采用IDictionary(非泛型),你没有在那里使用任何类型特定于{ {1}}或T

然后,您可以简单地将所有参数转换为U

IDictionary

您可能还需要修改var d = arg as IDictionary; if (d != null) { var res = DictionaryToString(d); } 实施:

DictionaryToString

或者,如果你真的想使用LINQ,你可以尝试转换为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); } (它不可能转换为其他任何东西,因为这可能是一个通用字典(dynamic)或非通用散列表(KeyValuePair<>)):

DictionaryEntry

这基本上是&#34;鸭子类型&#34;存在var valueStrings = d.Cast<dynamic>().Select(de => de.Key.ToString() + ": " + de.Value.ToString()); return string.Join("\n", valueStrings); Key属性。

答案 1 :(得分:1)

这听起来可能是旧System.Collections命名空间的情况:

    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();
    }

<强>推理:

非通用IDictionary将是键值对的集合,其中键为object,值为objectobject支持ToString的所有实例,因此集合的所有键和值都可以在不知道其特定类型的情况下转换为string

这不起作用的原因:

var castValue = value as Dictionary<,>

是因为泛型类型Dictionary<TKey, TValue>需要2个类型参数。如果没有这些类型参数,则集合不是通用的。如果您在编译时不知道键或值类型,那么最好使用非泛型IDictionary

答案 2 :(得分:0)

GetGenericTypeDefinition可用于以前的版本http://msdn.microsoft.com/en-us/library/system.type.getgenerictypedefinition(v=vs.100).aspx。我认为MSDN上的4.5页缺少“其他版本”下拉列表。

答案 3 :(得分:0)

为什么不呢?

if ((value !=null) && value.GetType().IsGenericType &&
       value.GetType().GetGenericTypeDefinition() == typeof (Dictionary<,>))
{
   return DictionaryToString(castValue);
}
else
{
  return value.ToString();
}

答案 4 :(得分:0)

您可以在.NET 4.0中强制转换为dynamic。先前的typeof(Dictionary<,>)检查将确保您不会遇到运行时错误。

var castValue = value as dynamic;
return DictionaryToString(castValue);