C# 如何在不知道C中的底层类型的情况下遍历数组#
假设我有一个对象集合,其中一些是数组 我想将所有的值合并以打印它们,但我不知道数组中元素的类型C# 如何在不知道C中的底层类型的情况下遍历数组#,c#,arrays,casting,ienumerable,C#,Arrays,Casting,Ienumerable,假设我有一个对象集合,其中一些是数组 我想将所有的值合并以打印它们,但我不知道数组中元素的类型 foreach(var item in myList) { var val = item.Property; if (val.GetType().IsArray) { var array = val as IEnumerable<object>; val = string.Join(",", array); } DoS
foreach(var item in myList)
{
var val = item.Property;
if (val.GetType().IsArray)
{
var array = val as IEnumerable<object>;
val = string.Join(",", array);
}
DoSomething(val);
}
foreach(myList中的变量项)
{
var val=项目属性;
if(val.GetType().IsArray)
{
var数组=作为IEnumerable的val;
val=string.Join(“,”数组);
}
剂量测定法(val);
}
如果val包含字符串[]
,则此代码段也适用于myClass[]
但如果它包含一个int[]
或double[]
,那么数组将为null,这意味着动态强制转换失败
如果int或double是从System.TypeValue继承的,而System.TypeValue是从object继承的,那么这个代码段为什么不起作用呢
我怎样才能做到呢
编辑:将代码段更改为更显式,并避免出现错误的变量用法,因为我错误地简化了代码。在C#中不允许这样做,更多详细信息。 但您可以强制转换为非泛型
IEnumerable
,然后在按下string.Join()之前将所有内容强制转换为object:
foreach(myList中的var val)
{
if(val.GetType().IsArray)
{
变量数组=(IEnumerable)val;
//不允许设置val变量,但我假设这只是一个示例
val=string.Join(“,”,array.Cast());
}
}
首先,尝试在foreach
循环中分配给val
将不起作用。无法更改正在迭代的集合
所以你需要建立一个新的收藏。类似这样的工作原理,请参见迭代器中的yield return
语句如何让您构建叶对象的新IEnumerable
,并在任何级别上同时适用于对象和值类型
class Program
{
static void Main(string[] args)
{
var myWackyList = new object[] {
new[]{1d, 2d},
3d,
new[]{4d, 5d},
new []
{
new[]
{
6d
}
},
"7",
new[]{ "8", "9"}
};
Console.WriteLine( string.Join(", ", Flatten( myWackyList )));
}
static IEnumerable<object> Flatten(IEnumerable enumerable)
{
foreach (var val in enumerable)
{
if ( val.GetType().IsArray )
foreach ( var flattenedVal in Flatten( val as IEnumerable ) )
yield return flattenedVal;
else
yield return val;
}
}
}
类程序
{
静态void Main(字符串[]参数)
{
var myWackyList=新对象[]{
新[]{1d,2d},
3d,
新[]{4d,5d},
新[]
{
新[]
{
6d
}
},
"7",
新[]{“8”,“9”}
};
Console.WriteLine(string.Join(“,”,Flatten(myWackyList));
}
静态IEnumerable展平(IEnumerable enumerable)
{
foreach(可枚举中的var val)
{
if(val.GetType().IsArray)
foreach(变平中的变平val(val为IEnumerable))
收益率平坦化;
其他的
收益率;
}
}
}
如果您只是担心数组的一般性,或者更好的是IEnumerable
(根据您的演员阵容),那么我建议将签出的反射部分保留,只需尝试转换为IEnumerable
foreach (var val in myList)
{
if (val is IEnumerable enumeration)
{
string.Join(",", array); //You can't use val (as per your example because it's the element of the loop)
}
}
老实说,我不知道你打算对数组做什么,因为你把它作为一个对象添加到一个字符串中,这将是array,array,array…
等等。我将发布一个更好的解决方案,但是我不确定它是否是你想要的,因为你上面所做的没有多大意义
var notSureWhyStringBuilder = new StringBuilder();
foreach (var val in myList)
{
if (val is IEnumerable enumeration)
{
notSureWhyStringBuilder.Append($",{enumeration.ToString()}");
}
}
Console.WriteLine(notSureWhyStringBuilder.ToString());
现在,至少我觉得你更倾向于你想要的方向,但这对我来说并不合适,因为我不知道你会从中得到什么
我将再发布一个示例,它将为您迭代并将内部枚举构建到字符串中。我不知道或者假设这就是你想要的,但是在我提供的3个例子中,希望你可以去掉并重新设计它,以得到你需要的,并可能从中学习
var notSureWhyStringBuilder = new StringBuilder();
foreach (var val in myList)
{
if (val is IEnumerable enumeration)
{
foreach (var innerEnumeration in enumeration)
{
notSureWhyStringBuilder.Append($",{innerEnumeration.ToString()}");
}
}
}
Console.WriteLine(notSureWhyStringBuilder.ToString());
这里有一个小的控制台应用程序,我把它放在一起供你摆弄。复制并粘贴原样,它应该可以工作
控制台应用程序
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
namespace Question_Answer_Console_App
{
class Program
{
private const string ShortTab = " ";
private static readonly List<object> ListOfObjects = new List<object>()
{
4,
"Michael",
new object(),
new Program(),
69.4,
new List<string>() {"Mathew", "Mark", "Luke", "John" },
new int[] { 1, 3, 5, 7, 9 }
};
static void Main(string[] args)
{
var itemsText = new StringBuilder();
var arrayCounter = 0;
foreach (var item in ListOfObjects)
{
if (item is IEnumerable enumeration)
{
itemsText.AppendLine($"Array: {++arrayCounter}");
if (item is string text)
{
itemsText.AppendLine($"{ShortTab}{text}");
}
else
{
foreach (var innerItem in enumeration) itemsText.AppendLine($"{ShortTab}{innerItem.ToString()}");
}
}
}
Console.WriteLine(itemsText.ToString());
Console.Read();
}
}
}
不能将值类型数组强制转换为IEnumerable,因为只有在不需要表示转换的情况下,方差才适用。因此,它不适用于值类型。在这种特殊情况下,这种转换意味着装箱
我会这样做,以防止不必要的拳击,如在案件与铸造,例如
public static string Stringify(this object o, string delimiter)
{
if (!(o is IEnumerable enumerable))
return o.ToString();
var sb = new StringBuilder();
foreach (var i in enumerable)
{
if (sb.Length > 0)
sb.Append(delimiter);
sb.Append(i.ToString());
}
return sb.ToString();
}
@Maess double和int是对象,但它们也是值类型(不是原语),因此不能涉及方差。是的,对不起,我简化了代码,没有看到我在foreach循环中使用了相同的val
变量名。非常感谢,IEnumerable
类没有出现,我注意到它不在同一个名称空间中,这使我走错了方向。这个很有魅力!谢谢你的详细回答。在这种情况下,我的目标是使用反射在控制台上打印对象的所有属性的值。我想处理值是一个值数组的情况,然后简单地用分隔符连接这些值。我希望代码尽可能通用,因为我在设计时不知道数组中会有什么类型的值,这取决于我处理的对象。@Sierramike没有问题。您可能希望使用递归函数,因为如果这些数组包含数组而不是字符串,该怎么办。为了速度和资源,我建议使用stringbuilder。反思很有趣:)坚持下去。
Array: 1
Michael
Array: 2
Mathew
Mark
Luke
John
Array: 3
1
3
5
7
9
public static string Stringify(this object o, string delimiter)
{
if (!(o is IEnumerable enumerable))
return o.ToString();
var sb = new StringBuilder();
foreach (var i in enumerable)
{
if (sb.Length > 0)
sb.Append(delimiter);
sb.Append(i.ToString());
}
return sb.ToString();
}