无法在通用 tostring 方法 C# 中推断类型
Can't infer type in generic tostring method C#
我有一个自定义辅助方法,它接受一个值并确定其类型。如果它是一个可以被枚举的数据结构,那么它会被传递给相应的 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 ();
}
它不再抛出错误。
编辑:它没有按预期工作;它改为在传递给它的每个对象上调用 GetString()
的通用 .ToString()
版本,而不是更具体的重载(如果它在其他方面适用)。将 List
对象传递给 returns 字符串 System.Collections.Generic.List'1[System.String]
。而不是列表的内容。
快速修复您的解决方案(将值转换为其类型):
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();
你不需要在这里使用泛型,你可以用非泛型集合接口定义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 + "}";
}
Array、List 和 IEnumerable 情况都将包含在 IEnumerable 重载中。注意:需要重载字符串,因为我们不想将其视为 IEnumberable。
以防万一,如果您尝试生成 json,您可以通过使用像 Json.NET 这样的库来避免很多痛苦,序列化对象并不像您想象的那么简单.
您可以创建名称相同但参数不同的方法,当您 运行 代码 C# 将根据您作为参数传递的类型选择正确的方法执行,您不需要测试它的类型。
您只需要两个重载,一个用于 IEnumerables
,它也涵盖 Lists
和 Arrays
,一个用于 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))
+ "}";
}
}
}
我有一个自定义辅助方法,它接受一个值并确定其类型。如果它是一个可以被枚举的数据结构,那么它会被传递给相应的 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 ();
}
它不再抛出错误。
编辑:它没有按预期工作;它改为在传递给它的每个对象上调用 GetString()
的通用 .ToString()
版本,而不是更具体的重载(如果它在其他方面适用)。将 List
对象传递给 returns 字符串 System.Collections.Generic.List'1[System.String]
。而不是列表的内容。
快速修复您的解决方案(将值转换为其类型):
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();
你不需要在这里使用泛型,你可以用非泛型集合接口定义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 + "}";
}
Array、List 和 IEnumerable 情况都将包含在 IEnumerable 重载中。注意:需要重载字符串,因为我们不想将其视为 IEnumberable。
以防万一,如果您尝试生成 json,您可以通过使用像 Json.NET 这样的库来避免很多痛苦,序列化对象并不像您想象的那么简单.
您可以创建名称相同但参数不同的方法,当您 运行 代码 C# 将根据您作为参数传递的类型选择正确的方法执行,您不需要测试它的类型。
您只需要两个重载,一个用于 IEnumerables
,它也涵盖 Lists
和 Arrays
,一个用于 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))
+ "}";
}
}
}