Я заканчиваю с большим количеством кода как это:
List<string> dates = someMethodCall();
foreach (string dateStr in dates) { }
Я обычно объявляю объект, по которому я выполняю итерации и затем использую его в foreach
условие из беспокойства это someMethodCall()
произошел бы для каждого повторения цикла. Имеет место это? Я предпочел бы делать это:
foreach (string dateStr in someMethodCall()) { }
Но я только хочу сделать это если someMethodCall()
происходит только однажды, и затем его результаты кэшируются для каждого последующего повторения.
Метод будет называться только один раз в обоих случаях.
Первый метод имеет преимущество читаемости, поскольку вы можете назвать переменную и описывать, что в нем с его именем. Это сделает код более самодоступным и улучшает ремонтопригодность.
Чтобы процитировать авторитетный источник по этому поводу:
Спецификация языка C # - 8.8.4. Выход
Foreach
Foreach (V v в X) встроенный оператор
затем расширяется до:
{ E e = ((c) (x)). Getnumerator (); пытаться { V v; в то время как (e.movenext ()) { v = (v) (t) e.current; Встроенное заявление } } наконец { ... // утилизировать e } }
Понятно, что выражение x
в вышеупомянутом выступлении
оценивается только один раз в расширении.
Мой подход похож на Адриан. Однако в моем случае контроллер никогда не работает с типами бетона зрения. Контроллер полностью отделен видом - таким же образом, как просмотраModel.
Как эти работы можно увидеть в примере просмотра моделя Framework WPF Framework (WAF) .
.
С наилучшими пожеланиями,
JBE
-121--1001609- Foreach
Оценка сбора будет оценивать коллекцию один раз, получить итератор, а затем использовать это для его итерации.
Кроме того, я не уверен, что является вашим применением, но если вы беспокоитесь о количестве кода, лямбдас может помочь убрать в некоторых случаях.
Например, если вы пишете SOREACH
заявления, чтобы просто искать определенные элементы списка, рассмотрите возможность использования лямбда. Я обнаружил, что используя их, когда это уместно, уменьшило количество кода, которое я написал и сделал его более читаемым в определенных ситуациях.
Один из способов запомнить, как это работает, чтобы рассмотреть это: итератор не будет работать, если он продолжат вызывать ваш метод снова и снова.
Ваш метод возвращает список элементов. Если цикл продолжал вызывать свой метод снова и снова, он будет (запрещать побочные эффекты), продолжайте возвращаться таким же списком. Как будет знать цикл, на втором звонке, что он уже обработал первый элемент в списке?
Все, что вы можете перечислить, имеет метод Getnumerator ()
, который должен вернуть тип ( Обычно тип реализации IEnumerator, , но это не должно быть ). Возвращенный тип должен иметь текущее свойство
и метод MOVENEXT ()
.
Возвращенный тип - это ваш объект enumerator, и ваша петля Foreach содержит ссылку на , что объект перечисления , как он перечисляет. Он продолжает вызывать тока
и и
MOVENEXT ()
на этом объекте enumerator до MOVENEXT ()
возвращает false.
Использование Foreach
, как правило, более читаемо и удобно, но вы также можете перечислять «вручную», если хотите:
List<string> dates = someMethodCall();
IEnumerator<string> myEnumerator = dates.GetEnumerator();
while (myEnumerator.MoveNext())
{
// do something with myEnumerator.Current
}
Я не самый лучший в чтении MSIL, но я сделал некоторые тестирования, и, похоже, согласны с тем, что все говорят: коллекция восхищает только один раз. См. Ниже для MSIL, если вам интересно.
public static void ATest() {
foreach (string s in GetSomeStrings()) {
Console.WriteLine(s);
}
}
public static void BTest() {
string[] strings = GetSomeStrings();
foreach (string s in strings) {
Console.WriteLine(s);
}
}
public static string[] GetSomeStrings() {
return new string[] {
"string1", "string2", "string3"
};
}
ATEST () MSIL:
.method public hidebysig static void ATest() cil managed
{
.maxstack 2
.locals init (
[0] string s,
[1] string[] CS$6$0000,
[2] int32 CS$7$0001,
[3] bool CS$4$0002)
L_0000: nop
L_0001: nop
--->L_0002: call string[] EdProgAppData_BLL.Common::GetSomeStrings()
L_0007: stloc.1
L_0008: ldc.i4.0
L_0009: stloc.2
L_000a: br.s L_001d
L_000c: ldloc.1
L_000d: ldloc.2
L_000e: ldelem.ref
L_000f: stloc.0
L_0010: nop
L_0011: ldloc.0
L_0012: call void [mscorlib]System.Console::WriteLine(string)
L_0017: nop
L_0018: nop
L_0019: ldloc.2
L_001a: ldc.i4.1
L_001b: add
L_001c: stloc.2
L_001d: ldloc.2
L_001e: ldloc.1
L_001f: ldlen
L_0020: conv.i4
L_0021: clt
L_0023: stloc.3
L_0024: ldloc.3
L_0025: brtrue.s L_000c
L_0027: ret
}
BTEST () MSIL:
.method public hidebysig static void BTest() cil managed
{
.maxstack 2
.locals init (
[0] string[] strings,
[1] string s,
[2] string[] CS$6$0000,
[3] int32 CS$7$0001,
[4] bool CS$4$0002)
L_0000: nop
--->L_0001: call string[] EdProgAppData_BLL.Common::GetSomeStrings()
L_0006: stloc.0
L_0007: nop
L_0008: ldloc.0
L_0009: stloc.2
L_000a: ldc.i4.0
L_000b: stloc.3
L_000c: br.s L_001f
L_000e: ldloc.2
L_000f: ldloc.3
L_0010: ldelem.ref
L_0011: stloc.1
L_0012: nop
L_0013: ldloc.1
L_0014: call void [mscorlib]System.Console::WriteLine(string)
L_0019: nop
L_001a: nop
L_001b: ldloc.3
L_001c: ldc.i4.1
L_001d: add
L_001e: stloc.3
L_001f: ldloc.3
L_0020: ldloc.2
L_0021: ldlen
L_0022: conv.i4
L_0023: clt
L_0025: stloc.s CS$4$0002
L_0027: ldloc.s CS$4$0002
L_0029: brtrue.s L_000e
L_002b: ret
}