如何在不知道C#中的底层类型的情况下通过数组进行迭代

时间:2018-05-25 13:17:37

标签: 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);
    }
    DoSomething(val);
}

如果val包含string[],则此代码段也适用于myClass[]

但如果它包含int[]double[],则数组将为null,表示动态转换失败。

如果从继承自object的System.TypeValue继承int或double,为什么不对此代码段起作用?

我怎么能实现呢?

编辑:将代码段更改为更明确,并避免错误的变量用法,因为我错误地简化了我的代码。

4 个答案:

答案 0 :(得分:2)

在C#中不允许这样做,更多细节here。 但是您可以转换为非泛型 IEnumerable,然后在推送到string.Join()之前将所有内容转换为对象:

foreach(var val in myList)
{
    if (val.GetType().IsArray)
    {
        var array = (IEnumerable)val;
        // It's not allowed to set val variable, but I assume it's just an example
        val = string.Join(",", array.Cast<object>());
    }
}

答案 1 :(得分:0)

首先,尝试在val循环内分配foreach将无法正常工作。您无法更改正在迭代的集合。

所以你需要建立一个新的集合。这样的工作,看看迭代器中的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;
            }
        }
    }

答案 2 :(得分:0)

如果你只是担心一般的阵列,或者更好的是IEnumerable(根据你的演员阵容)那么我建议将支票的反射部分留下来,只是试图转换为{{1} }。

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...

现在,至少我觉得你更倾向于你想要的方向,但是我不能很好地和我坐在一起,因为我不知道你是怎么回事。重新获得它。

我将发布另一个示例,一个将迭代并为您构建字符串内部枚举的示例。我不知道或假设你想要什么,但在我提供的3个例子之间,我希望你可以带走并重新设计它以获得你需要的东西,并从中学到它。 / p>

var notSureWhyStringBuilder = new StringBuilder();
foreach (var val in myList)
{
    if (val is IEnumerable enumeration)
    {
        notSureWhyStringBuilder.Append($",{enumeration.ToString()}");
    }
}
Console.WriteLine(notSureWhyStringBuilder.ToString());

这是一个小型的控制台应用程序,我把它放在一起让你捣乱。按原样复制并粘贴它,它应该可以工作。

控制台应用

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

答案 3 :(得分:0)

您无法将值类型数组强制转换为IEnumerable,因为只有在不需要代表性转换的情况下,方差才适用。因此,它不适用于价值类型。在这种特殊情况下,这种转换意味着拳击。

我会这样做以防止不必要的装箱,例如Cast中的情况。

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