Gå til innhold

Anbefalte innlegg

Ble lei av å måtte kjøre IEnumerables.ToList() for å kunne bruke .ForEach(action). Så tenkte jeg kunne være lur å lage min egen vri:

   public static IEnumerable<TSource> ForEach<TSource>(
	   this IEnumerable<TSource> source, 
	   Action<TSource> action)
  {
   foreach(TSource e in source)
   {
	   action.Invoke(e);
	   yield return e;
   }
  }

 

Men... den fungerte ikke. Virker ikke som den blir kjørt en gang. Og jeg fatter ikke hvorfor. Testet den slik:

	   var range = Enumerable.Range(1, 10).Select(ø => ø.ToString());
   range.ForEach(ø => Console.WriteLine(ø));

Men ingenting skrives ut. Setter den til å breake på ForEach metoden, men det breakes ikke. Hvis jeg derimot setter retur typen til void og fjerner yield return e, slik:

   public static void ForEach<TSource>(
	   this IEnumerable<TSource> source, 
	   Action<TSource> action)
  {
   foreach (TSource e in source)
   {
	   action.Invoke(e);
   }
  }

Da kjøres den som den skal, tallene skrives ut og den breaker hvis jeg setter breakpoint på ForEach moetoden. Hvorfor det? I don't get it... er det noe jeg har gått glipp av her? :hmm:

 

(Grunnen til yield return osv, var at jeg tenkte det kunne være kjekt å neste den etter en while for eksempel og så videre med noe annet, slik en kan gjøre med de fleste andre IEnumerable extension metodene.)

Endret av Svish
Lenke til kommentar
Videoannonse
Annonse

Jeg gjorde ingen endringer i koden din!

 

	public static class RangeStatic
{
	public static IEnumerable<TSource> ForEach<TSource>(
	   this IEnumerable<TSource> source,
	   Action<TSource> action)
	{
		foreach (TSource e in source)
		{
			action.Invoke(e);
			yield return e;
		}
	}
}

 

Jeg kjørte en test.

 

		[Test]
	public void Test()
	{
		var range = Enumerable.Range(1, 10).Select(ø => ø.ToString());

		var resultat = range.ForEach(Console.WriteLine);

		Assert.AreEqual(10, resultat.Count());
	}

 

Det fungerer fint her!

 

Se resultat:

Test : Passed*** ConsoleOutput ***
1
2
3
4
5
6
7
8
9
10

Lenke til kommentar

Ja, fant ut av det til slutt. Virker som det har med Deffered Execution å gjøre. Tror koden kjøres hos deg når du bruker Assert.AreEqual(10, resultat.Count()), ettersom Count() vil måtte kjøre igjennom sekvensen for å finne ut hvor mange det er.

 

Uansett synes jeg det var litt teit. kompilatoren kunne jo godt funnet ut at jeg ikke skulle noe mer med den saken, og derfor kjørt den eller noe... men det hadde sikkert blitt kluss det også :p markerer nå denne som løst uansett, hehe.

Lenke til kommentar

Det er helt korrekt at det er pga deferred execution. Grunnen til at det fungerer på denne måten er pga at man blant annet på denne måten i visse tilfeller kan spare en del minnebruk (hvis jeg ikke husker helt riv ruskende galt fra en artikkel av Anders Hejlsberg). IEnumerable er forøvrig ingen collection nødvendigvis (satt litt på spissen kanskje), og derfor er logikken bak ditt første forsøk litt inkonsistent.

Endret av The Jackal
Lenke til kommentar

Altså...yield return brukes når du skal kunne bruke funksjonen i en foreach. For at ditt første forsøk skulle fungert, måtte du brukt denne koden:

 

var range = Enumerable.Range(1, 10).Select(ø => ø.ToString());

foreach(int i in range.ForEach(ø => Console.WriteLine(ø)))

{

<code>

}

-----------------

Når du bare skriver:

range.ForEach(ø => Console.WriteLine(ø));

 

så oppfører den seg egentlig som:

var range = Enumerable.Range(1, 10).Select(ø => ø.ToString());

 

range er her ikke evaluert enda. Hvis du ønsker å utføre en action på hvert item uten å bruke en foreach, må du som du fant ut, skrive om funksjonen til void og ta bort yield return. Hvis du ønsker å kunne bruke funksjonen i en foreach setning så skal den returnere T og bruke yield return.

 

Litt knotete forklart dette...men du skjønner kanskje :)

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...