2017-01-05 4 views
1

В C#, я хочу взять массив типа «Т» где я знаю, что «T» поддерживает интерфейс «IMyInterface» и:В C#, как я могу преобразовать свой массив из IEnumerable <IMyInterface> в IEnumerable <T>?

  1. Cast как массив «IMyInterface»
  2. вызовов метод в этом массиве, который будет фильтровать список
  3. Верните его в исходный список типов T.

1 и 2 выше работают нормально, но я столкнулся с проблемами на шаге 3.

Вот мой код:

IEnumerable<IMyInterface> castedArray = originalTypedArray as IEnumerable<IMyInterface>; 

if (castedArray != null) 
{ 
    var filteredArray = castedArray.Where(r => r.Ids.Contains(MyId)).ToList(); 

    IEnumerable<T> castedBackToOriginalTypeArray = filteredArray as IEnumerable<T>; 
    if (castedBackToOriginalTypeArray == null) 
    { 
      current = new List<T>(); 
    } 
    else 
    { 
     current = castedBackArray; 
    } 

    // I need to cast back, because only my Type T has the .Id property 
    List<int> ids = current.Select(r => r.Id).ToList(); 
} 

Вопрос находится на этой линии:

IEnumerable<T> castedBackToOriginalTypeArray = filteredArray as IEnumerable<T>; 

Это всегда, кажется, вернуть нуль (вместо отфильтрованного массива отбрасывать обратно IEnumerable < T>.

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

+0

Работает ли от 'T' до' IMyInterface' без IEnumerable? – kat1330

+2

Зачем вам вообще бросать? Не можете ли вы отфильтровать исходный 'IEnumerable '? –

+0

@LucMorin - Я делаю фильтр на IEnumerable , но мне нужно его вернуть обратно к исходному типу, потому что от него зависит моя следующая строка кода. Я обновил вопрос, чтобы сделать это более ясным – leora

ответ

2

Это работает для меня:

public class A : IA { 

} 


public interface IA { 

} 

List<A> l = new List<A> { new A(), new A(), new A() }; 
IEnumerable<IA> ias = l.Cast<IA>(); 
IEnumerable<A> aTypes = ias.Cast<A>(); 
+0

Нет необходимости перебирать всю коллекцию для каждого объекта.Это также приведет к сбою, если в коллекции содержится что-то, что * не * a 'T' (и, следовательно, почему преобразование' as' возвращает null) – Rob

+0

@Rob OP специально сказал: 'Я хочу взять массив типа T, где я знаю, что «T» поддерживает интерфейс «IMyInterface», поэтому почему он сбой. – CodingYoshi

+0

Потому что потенциально «фильтрация» может добавить что-то в коллекцию. Здесь нет никакой безопасности. Фактически, наложение не требуется, если вы можете * доказать *, что в коллекции будет содержаться только 'T'. – Rob

0

Либо вам не нужно, чтобы бросить его в IEnumerable<IMyInterface>, или наработка правильно помешали вам писать код ошибочный.

Давайте возьмем меньший пример:

void SomeMethod<T>(IEnumerable<T> originalTypedArray, int MyId) 
    where T : class, IMyInterface 
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this is important 
{ 
    if (originalTypedArray != null) 
    { 
     var filteredArray = originalTypedArray.Where(r => r.Ids.Contains(MyId)); 

     // No need to cast to `IEnumerable<T>` here - we already have ensured covariance 
     // is valid in our generic type constraint 
     DoSomethingExpectingIEnumerableOfIMyInterface(filteredArray); 
    } 
} 
void DoSomethingExpectingIEnumerableOfIMyInterface(IEnumerable<IMyInterface> src) 
{ 
    foreach (var thing in src) 
    { 

    } 
} 

Однако, если вы не получать коллекцию как IEnumerable<T>, то среда выполнения правильно провалив ролях:

void SomeMethod<T>(IEnumerable<IMyInterface> originalTypedArray, int MyId) 

Мы могли бы дайте ему кучу IEnumerable<Apple> при условии, что Apple : IMyInterface. Затем вы пытаетесь направить его на IEnumerable<T>, где T = Banana и стрела, код сломан.