2014-12-14 3 views
0

Я только начал изучать C# и я немного путать с следующим фрагментом кода из MSDN:Как C# определяет, какую реализацию использовать для IEnumerable?

IEnumerable<string> strings = 
      Enumerable.Repeat("I like programming.", 15); 

Поскольку IEnumerable является интерфейсом и Enumerable.Repeat <>() возвращает IEnumerable типа, как это " строки "реализованы? Как список или что-то еще контейнер?

+3

Просто найдите источник: http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,e2850cfe2b0cc87f –

+0

Внутренняя работа любого перечислимы намеренно скрыты от конечного пользователя. Как правило, будет какая-то внутренняя коллекция (например, список), но вы не должны точно знать. В этом случае достаточно цикла с выражениями 'yield' и использовать меньше памяти. – ja72

ответ

0

Внутренний сбор в этом случае отсутствует. Фактически, некоторые перечисления могут быть бесконечными, поэтому вы не всегда можете ожидать внутренней коллекции. В этом конкретном методе есть поле, которое содержит значение, и цикл, который подсчитывает, сколько раз будет вызываться следующий. Если он попадает в указанный счетчик, он останавливает итерацию. Конечно, это реализовано с использованием функции итераторов C#, которая делает реализацию тривиальной.

0

Это детали реализации. Подпись Enumerable<string>.Repeat() обещает результат IEnumerable<string>, и это то, что он возвращает.

Является ли это значение возвратом в виде массива, List или сгенерировано каким-либо другим способом (в последнем случае), который реализует требуемый IEnumerable<T>, не имеет значения. См. Раздел «Замечания» на MSDN, хотя:

Этот метод реализуется с использованием отложенного выполнения. Непосредственное возвращаемое значение - это объект, который хранит всю информацию, необходимую для выполнения действия. Запрос, представленный этим методом, не выполняется до тех пор, пока объект не будет перечислен, либо вызвав его метод GetEnumerator напрямую, либо используя foreach в Visual C# или для каждого в Visual Basic.

Если вас интересует фактическая реализация, см. the proposed duplicate.

0

В настоящее время в любом случае, тип Возвращается:

Enumerable/'<RepeatIterator>d__b5`1'<string>. 

Вы не можете определить переменную как то Tpye, потому что это анонимный тип. Анонимные типы реализуются путем компиляции типа с именем, в то время как действительный .NET недействителен C#, поэтому вы не можете случайно создать другой тип с тем же именем.

Этот особый анонимный тип - это сортировка, используемая для реализации yield. Опять же, когда вы код yield в C#, это скомпилировано путем создания классов .NET, которые реализуют IEnumerable и IEnumerator.

Ваш код не заботится ни о чем из этого, он просто заботится о том, чтобы он получил что-то, реализующее интерфейс.

Для этой точки рассмотреть действительность:

public IEnumerable<string> SomeStrings() 
{ 
    if(new Random().Next(0, 2) == 0) 
    return new HashSet<string>{"a", "b", "c"}; 
    else 
    return new List<string>{"a", "b", "c"}; 
} 

телефонный код не будет знать, если он получил HashSet<string> или ее List<string> и не будет заботиться. Не волнует, вернет ли версия 2.0 string[] или использует yield.

Вы можете создать свой собственный Repeat следующим образом:

public static IEnumerable<T> Repeat<T>(T element, int count) 
{ 
    while(count-- > 0) 
    yield return element; 
} 

У нас есть осложнения, хотя в том, что мы хотим, брошенной исключение, если count меньше нуля.Мы не можем просто сделать:

public static IEnumerable<T> Repeat<T>(T element, int count) 
{ 
    if(count < 0) 
    throw new ArgumentOutOfRangeException("count"); 
    while(count-- != 0) 
    yield return element; 
} 

Это не работает, потому что бросок не будет, пока мы фактически не перечислить его (если мы когда-нибудь сделать), как yield -определенных перечисления не запускать любой код, пока не найдешь первое перечисление. Поэтому нам нужно;

public static IEnumerable<T> Repeat<T>(T element, int count) 
{ 
    if(count < 0) 
    throw new ArgumentOutOfRangeException("count"); 
    return RepeatImpl<T>(element, count); 
} 
private static IEnumerable<T> RepeatImpl<T>(T element, int count) 
{ 
    while(count-- != 0) 
    yield return element; 
} 
Смежные вопросы