无法推断通用tostring方法中的类型C#

时间:2015-02-12 03:03:39

标签: c# types type-inference

我有一个自定义辅助方法,它接受一个值,并确定其类型。如果它是一个可以枚举的数据结构,那么它将被传递到各自的ToString方法以进行打印。但如果没有,则调用内置.ToString()方法。

public static String GetString<T> (T value)
{
    Type t = typeof(T);
    if (t.IsSubclassOf (typeof(IDictionary)))
        return _GetString_Dictionary(value);
    else if (t.IsSubclassOf (typeof(IEnumerable)))
        return _GetString_Enumerable (value);
    else
        return value.ToString ();
}

但是,我遇到了很多错误,这些错误与每次调用其他方法时无法推断参数类型有关。我目前没有主动如何解决这个问题;它甚至可以完成吗?

以上是上面调用的其他toString方法,供参考;

private static String _GetString_Dictionary<KT, VT> (Dictionary<KT, VT> d)
{
    string s = "{";
    foreach (var pair in d)
        s += GetString(pair.Key) + " : " + GetString(pair.Value) + ", ";
    return s.Substring (0, s.Length - 2) + "}";
}

private static String _GetString_Enumerable<T> (IEnumerable<T> e)
{
    string s = "[";
    foreach (T i in e)
        s += GetString(i) + ", ";
    return s.Substring(0, s.Length-2) + "]";
}

编辑:根据Equiso的信息缩短代码。


根据David Manning的例子,我修改了代码看起来像这样;

public static String GetString<KT, VT> (Dictionary<KT, VT> d)
{
    string s = "{";
    foreach (var pair in d)
        s += GetString(pair.Key) + " : " + GetString(pair.Value) + ", ";
    return s.Substring (0, s.Length - 2) + "}";
}

public static String GetString<T> (IEnumerable<T> e)
{
    string s = "[";
    foreach (T i in e)
        s += GetString(i) + ", ";
    return s.Substring(0, s.Length-2) + "]";
}

public static String GetString<T> (T value)
{
    return value.ToString ();
}

它不再抛出错误。

编辑:它不按预期工作;相反,它会在传递给它的每个对象上调用.ToString()版本的GetString(),而不是在其他情况下更具体的重载。将List对象传递给它会返回字符串System.Collections.Generic.List'1[System.String]。而不是列表的内容。

3 个答案:

答案 0 :(得分:1)

快速修复您的解决方案(将值转换为其类型):

public static String GetString<T> (T value)
{
  Type t = typeof(T);
  if (t.IsSubclassOf (typeof(Array)) || t.IsSubclassOf (typeof(IList)))
    return _ToString_List ((List)value);
  else if (t.IsSubclassOf (typeof(IDictionary)))
    return _ToString_Dictionary((Dictionary)value);
  else if (t.IsSubclassOf (typeof(IEnumerable)))
    return _ToString_Enumerable ((IEnumerable)value);
  else
    return value.ToString ();
}

更优雅的解决方案是使用扩展方法

public static class ToStringExtension()
{
  publicstatic String MyToString<T> (this T[] a) 
  {
  if (a.Length == 0)
    return "[]";
  string s = "[";
  for (int i=0; i<a.Length - 1; i++)
    s += GetString(a [i]) + ", ";
  return s + a [a.Length - 1] + "]";
  }

  public static String MyToString<KT, VT> (this Dictionary<KT, VT> d)
  {
  string s = "{";
  foreach (var pair in d)
    s += GetString(pair.Key) + " : " + GetString(pair.Value) + ", ";
  return s.Substring (0, s.Length - 2) + "}";
  }

  public static String MyToString<T> (this IEnumerable<T> e)
  {
  string s = "[";
  foreach (T i in e)
    s += GetString(i) + ", ";
  return s.Substring(0, s.Length-2) + "]";
  }
}

使用扩展方法:

var arr = new string[10];
arr.MyToString();

答案 1 :(得分:1)

您不需要在此处使用泛型,您可以使用非泛型集合接口定义GetString,编译器会将您的调用绑定到最具体的集合。例如:

public static String GetString(object value) {

    if (value is string) {
        return value as string;
    } else if (value is IDictionary) {
        return GetString(value as IDictionary);
    } else if (value is IEnumerable) {
        return GetString(value as IEnumerable);
    } else {
        return value.ToString();
    }

}

public static String GetString(string l) {
    return l;
}

public static String GetString(IEnumerable l) {
    string s = "[";
    foreach (object i in l) {
        s += GetString(i) + ", ";
    }
    if (s != "[") s = s.Substring(0, s.Length - 2);
    return s + "]";
}

public static String GetString(IDictionary d) {
    string s = "{";
    foreach (object key in d.Keys) {
        s += GetString(key) + " : " + GetString(d[key]) + ", ";
    }
    if (s != "{") s = s.Substring(0, s.Length - 2);
    return s + "}";
}

IEnumerable重载将涵盖Array,List和IEnumerable案例。注意:需要对String进行重载,因为我们不希望将其视为IEnumberable。

答案 2 :(得分:1)

以防万一,如果你试图生成json,你可以通过使用像Json.NET之类的库来节省很多痛苦,序列化对象并不像你想象的那么简单。


您可以创建具有相同名称但不同参数的方法,并且在运行代码时,C#将根据您作为参数传递的类型选择要执行的方法,您不需要测试它的类型。

您只需要两个重载,一个用于IEnumerables,其中包含ListsArrays,还有一个用于Dictionary

此外,您可以使用一些框架方法来连接字符串string.Join,这将仅在元素之间添加分隔符,因此您不必担心删除尾随逗号。

这是一个小工作示例

using System;
using System.Collections.Generic;
using System.Linq;

namespace Experiments {
    class Program {
        static void Main(string[] args) {
            var array = new[] { "one", "two", "three" };
            var list = new List<string> { "four", "five", "six" };
            var dictionary = new Dictionary<string, string> {
                {"k1", "v1"},
                {"k2", "v2"},
                {"k3", "v2"},
            };

            Console.WriteLine(GetString(array));
            Console.WriteLine(GetString(list));
            Console.WriteLine(GetString(dictionary));

            Console.ReadLine();
        }

        public static string GetString<T>(IEnumerable<T> value) {
            return "["
                + string.Join(", ", value)
                + "]";
        }

        public static string GetString<TKey, TValue>(Dictionary<TKey, TValue> value) {
            return "{"
                + string.Join(", ", value.Select(entry => entry.Key + " : " + entry.Value))
                + "}";
        }
    }
}