Как перебрать массив, не зная базового типа в C # - PullRequest
0 голосов
/ 25 мая 2018

Допустим, у меня есть коллекция объектов, некоторые из которых являются массивами.

Я хотел бы объединить все значения для их печати, но я не знаю тип элементов в массивах.

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[], томассив будет нулевым, что означает, что динамическое приведение не выполнено.

Если int или double наследуются от System.TypeValue, который наследуется от объекта, почему этот фрагмент кода не работает?

И какМогу ли я достичь этого?

Редактировать: изменил фрагмент кода, чтобы он был более явным и избегал неправильного использования переменных, которое показывалось, потому что я неправильно упростил свой код.

Ответы [ 4 ]

0 голосов
/ 25 мая 2018

Вы не можете преобразовать массив типа значения в 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();
}
0 голосов
/ 25 мая 2018

Во-первых, попытка присвоить 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;
            }
        }
    }
0 голосов
/ 25 мая 2018

Если вы просто беспокоитесь о массивах в целом или, что еще лучше, 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 примерами, которые я предоставляю, надеюсь, вы сможете отобрать и переработать его, чтобы получить то, что вам нужно, и, возможно, извлечь из него уроки.Вот небольшое консольное приложение, которое я собрал для вас, чтобы поиграть.Скопируйте и вставьте его как есть, и оно должно работать.

Консольное приложение

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

Выходы

Array: 1
  Michael
Array: 2
  Mathew
  Mark
  Luke
  John
Array: 3
  1
  3
  5
  7
  9
0 голосов
/ 25 мая 2018

Это не разрешено делать в C #, подробнее здесь .Но вы можете привести к неуниверсальному 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>());
    }
}
...