我有一个包含不同类型对象的数组,例如:
Object[] array = {"String_1", double 3.14, "String_2"};我想覆盖ToString(),这样当我在上面的数组上使用它时,它将显示对象类类型以及它们在数组中的数量,例如:
Object[] array = {"String_1", double 3.14, "String_2"};
Console.WriteLine(array.ToString()); // will print "String-2,Double-1"我需要一些帮助来做这件事:-)
发布于 2021-05-17 02:42:56
您不能为您不拥有的类编写自己的ToString实现,并且您也不拥有Array类。
您需要编写自己的方法将数组转换为您喜欢的格式。幸运的是,这在LINQ中是非常简单的。我们甚至可以让它成为一种扩展方法,让它看起来更自然
using System.Linq;
public static class ArrayExt
{
public static string ToCustomString(this object[] array)
{
var grouped = array.GroupBy(
c => c?.GetType(),
(type, vals) => $"{type?.Name ?? "null"}-{vals.Count()}"
);
var result = string.Join(",", grouped);
return result;
}
} 下面是它的用法示例:
object[] array = new object[] { 1, 2, "Three", 4.0f, "Five", 6M };
// extension method syntax
var value1 = array.ToCustomString();
// or static invocation sytanx
var value2 = ToCustomString(array);这将根据Type或null使用GroupBy对数组中的各个项进行分组。对每个组进行转换,这样我们现在就有了一个集合,其中每一项都是"{TypeNameOrNull}-{Count}"格式的字符串。然后我们将其传递给string.Join以构建一个组合字符串,并用逗号分隔每一项。
如果您知道您的阵列中不会有null,我们可以将上述操作简化为:
var grouped = array.GroupBy(
c => c.GetType(),
(type, vals) => $"{type.Name}-{vals.Count()}"
);
var result = string.Join(",", grouped);例如,如果您想要按每个类型/组的项目数对最终字符串进行排序,则需要一个更详细的版本,将GroupBy与OrderBy和Select相结合
var groupedAndOrdered = array
.GroupBy(
c => c.GetType(),
(type, vals) => new { Name = type.Name, Count = vals.Count() }
)
.OrderBy(c => c.Count)
.Select(c => $"{c.Name}-{c.Count}");
var result = string.Join(",", groupedAndOrdered);如果您不喜欢内置的类型名称(用Single代替float,用Int32代替integer),那么您需要编写一个包含将它们转换为首选文本的逻辑的方法:
public static string TypeToName(Type type) {
if (type == null) return "null";
if (type == typeof(float)) return "float";
if (type == typeof(int)) return "int";
// etc
return type.Name; // fallback
} 然后,您可以在构造字符串时使用它,例如:
var grouped = array.GroupBy(
c => c?.GetType(),
(type, vals) => $"{TypeToName(type)}-{vals.Count()}"
);
var result = string.Join(",", grouped);发布于 2021-05-16 21:27:18
对于重写,您需要从数组类型派生。但是你甚至不能从数组类型中派生出来。即使您将ToString()设置为扩展方法,默认的ToString()方法也将始终优先于扩展方法。在这里,您唯一的选择是创建一个带有覆盖的ToString()的自定义数组类型。
public class CustomArray
{
private object[] array;
public CustomArray(int size) => array = new object[size];
public CustomArray(object[] array) => this.array = array;
public object this[int index] { get => array[index]; set => array[index] = value; } //Indexer
public override string ToString()
{
var dict = new Dictionary<Type, int>();
foreach (var item in array)
{
Type type = item.GetType();
if (dict.ContainsKey(type))
{
dict[type]++;
}
else
{
dict[type] = 1;
}
}
return string.Join(", ", dict.Select(item => $"{item.Key.Name}: {item.Value}"));
}
}当然,您可以更深入地让您的自定义数组实现IEnumerable<T>、ICollection<T>和其他接口(参见this answer),使其与内置数组类型更加一致。
发布于 2021-05-16 23:12:23
为什么需要覆盖ToString
相反,可以编写一个函数来以所需的格式StringfyObjectArray和Map这些值。
https://stackoverflow.com/questions/67556887
复制相似问题