Приведение объекта к IEnumerable, где T неизвестно

Я пытаюсь играть с отражением и столкнулся со следующей ситуацией.

в следующем коде предположим, что " obj " может иметь типы IEnumerable<> или ICollection<> или IList<>.

Я хотел бы бросить эту систему.Возражаю IEnumerable<> всегда (как ICollection<> и IList<> наследовать от IEnumerable<> в любом случае), так что я хотел бы перечислить коллекцию и использовать отражение, чтобы писать отдельные элементы.

мотивация за этим я просто пытаясь увидеть, как сериализаторы, в общем, сериализуют данные, и поэтому я пытаюсь смоделировать эту ситуацию в надежде понять отражение.

Я подумал о том, чтобы бросить объект non-generic IEnumerable, но думал, что это вызовет ненужный бокс объектов, когда скажем, фактический экземпляр IEnumerable<int>...Правильно ли я думаю?

private void WriteGenericCollection(object obj)
    {
        Type innerType = obj.GetType().GetGenericArguments()[0];

        //Example: IEnumerable<int> or IEnumerable<Customer>
        Type generatedType = typeof(IEnumerable<>).MakeGenericType(innerType);

        //how could i enumerate over the individual items?
    }

2 ответов


Ну, поскольку вы не знаете фактический тип элементов до выполнения, вам не нужно использовать универсальный IEnumerable<T> интерфейс; просто используйте не общий,IEnumerable (общий наследуется от него):

private void WriteGenericCollection(object obj)
{
    IEnumerable enumerable = (IEnumerable)obj;
    foreach(object item in enumerable)
    {
        ...
    }
}

Ваш вопрос изобилует заблуждениями. Давайте разберемся с ними.

в следующем коде, предположим, что объект obj может быть IEnumerable<> или ICollection<> или IList<>.

если это правда, и если вы знаете тип enumerable, лучшим способом написания метода было бы

private void WriteGenericCollection<T>(IEnumerable<T> obj)
{
    // ...
}

я хотел бы опустить эту систему.Объект IEnumerable всегда (как ICollection и IList наследуют от IEnumerable в любом случае), поэтому что я хотел бы перечислить над коллекцией и использовать отражение написать отдельные пункты.

"наследовать" не является правильным термином, когда речь идет об интерфейсах; он также может дать вам неправильные идеи. Интерфейсы лучше всего рассматривать как контрактов: рассматривая возможность реализации интерфейса, вы можете только решить реализовать его как автор намеревался или не реализовать его вообще.

некоторые интерфейсы суперсеты других интерфейсов; их контракты говорят: "исполнители должны делать это в дополнение к чему-либо еще это контракт говорит". Но никогда нет никакого обмена, внедрения в наследство, потому что интерфейсы не имеют.

"Downcasting" также не является правильным термином для того, что вы делаете в этом методе. Downcasting означает приведение к более производному классу; есть также приведение к интерфейсу:

// Note: the method is still generic!
private void WriteGenericCollection<T>(object obj)
{
    var casted = (IEnumerable<T>)obj;
}

I мысль о понижении объекта до неродового IEnumerable, но думал, что это вызовет ненужный бокс объектов, когда допустим, фактический экземпляр IEnumerable...я правильно думаю?

бокс будет происходить если и только если объект был IEnumerable<T> здесь T это тип значения (числовой тип, a bool, an enum или struct). Если объект реализует IEnumerable<T> для некоторых известных T затем вы можете просто брось его на это. Если T неизвестно, затем бросил на неуниверсальный IEnumerable и возьмите возможный хит производительности (в любом случае нет никакого способа обойти его).

вам нужно будет использовать только отражение, если вы знаете ничего об объекте (в этом случае, конечно, вам также нужно иметь план для объектов, которые не могут быть перечислены, иначе зачем разрешать передавать их вашему методу в первую очередь?).