none
System.Linq.Select does not work, but HomeGrown ForEach does! RRS feed

  • Question

  • Why does not my call to select work?

    My homegrown ForEach works fine.

    Thanks

    Siegfried

    using System;
    using System.Linq;
    using System.Collections.Generic;
    using static System.Console;
    public static class MyExtensions {
        public static void ForEach<T>(this System.Collections.Generic.IEnumerable<T> a, Action<T> doit){ foreach (T ii in a) doit(ii); }
    }
    public class DictionarySelectBroken {
      public static void Main(string[] args){
          WriteLine("starting " + typeof(DictionarySelectBroken).Assembly.GetName().Name.ToString() + " /DictionarySelectBroken.cs clr=" + Environment.Version.ToString() + " os=" + Environment.OSVersion.Platform.ToString() + " v=" + Environment.OSVersion.ToString());
          var cvt = new Dictionary<string, Dictionary<string, string>>{{"c#", new Dictionary<string,string>{{"adInteger", "System.Int32"},
    				{"adDBTimeStamp", "System.DateTime"},
    				{"adVarWChar","string"}}},
    				{"tsql", new Dictionary<string,string>{{"adInteger", "System.Int32"},
    				{"adDBTimeStamp", "DATETIME"},
    				{"adSmallInt", "System.Int16"},
                                    {"adVarWChar","NVARCHAR"}}}};
          cvt["c#"].ForEach(p=> { WriteLine($"ForEach: key={p.Key} value={p.Value}"); /*return true; */} ) ; //works!
          cvt["c#"].Select(p=> { WriteLine($"Select: key={p.Key} value={p.Value}"); return true; } ) ; // Why does this not work?
      }
    }
    


    siegfried heintze

    Tuesday, January 22, 2019 10:49 PM

Answers

  • Hi,

    try to add to list:

    using System;
    using System.Linq;
    using System.Collections.Generic;
    using static System.Console;
    public static class MyExtensions {
        public static void ForEach<T>(this System.Collections.Generic.IEnumerable<T> a, Action<T> doit){ foreach (T ii in a) doit(ii); }
    }
    public class DictionarySelectBroken {
      public static void Main(string[] args){
          WriteLine("starting " + typeof(DictionarySelectBroken).Assembly.GetName().Name.ToString() + " /DictionarySelectBroken.cs clr=" + Environment.Version.ToString() + " os=" + Environment.OSVersion.Platform.ToString() + " v=" + Environment.OSVersion.ToString());
          var cvt = new Dictionary<string, Dictionary<string, string>>{{"c#", new Dictionary<string,string>{{"adInteger", "System.Int32"},
    				{"adDBTimeStamp", "System.DateTime"},
    				{"adVarWChar","string"}}},
    				{"tsql", new Dictionary<string,string>{{"adInteger", "System.Int32"},
    				{"adDBTimeStamp", "DATETIME"},
    				{"adSmallInt", "System.Int16"},
                                    {"adVarWChar","NVARCHAR"}}}};
          cvt["c#"].ForEach(p=> { WriteLine($"ForEach: key={p.Key} value={p.Value}"); /*return true; */} ) ; //works!
          cvt["c#"].Select(p=> { WriteLine($"Select: key={p.Key} value={p.Value}"); return true; } ).ToList() ; // Why does this not work?
      }
    }

    • Marked as answer by siegfried_ Wednesday, January 23, 2019 12:38 AM
    Tuesday, January 22, 2019 11:04 PM

All replies

  • Hi,

    try to add to list:

    using System;
    using System.Linq;
    using System.Collections.Generic;
    using static System.Console;
    public static class MyExtensions {
        public static void ForEach<T>(this System.Collections.Generic.IEnumerable<T> a, Action<T> doit){ foreach (T ii in a) doit(ii); }
    }
    public class DictionarySelectBroken {
      public static void Main(string[] args){
          WriteLine("starting " + typeof(DictionarySelectBroken).Assembly.GetName().Name.ToString() + " /DictionarySelectBroken.cs clr=" + Environment.Version.ToString() + " os=" + Environment.OSVersion.Platform.ToString() + " v=" + Environment.OSVersion.ToString());
          var cvt = new Dictionary<string, Dictionary<string, string>>{{"c#", new Dictionary<string,string>{{"adInteger", "System.Int32"},
    				{"adDBTimeStamp", "System.DateTime"},
    				{"adVarWChar","string"}}},
    				{"tsql", new Dictionary<string,string>{{"adInteger", "System.Int32"},
    				{"adDBTimeStamp", "DATETIME"},
    				{"adSmallInt", "System.Int16"},
                                    {"adVarWChar","NVARCHAR"}}}};
          cvt["c#"].ForEach(p=> { WriteLine($"ForEach: key={p.Key} value={p.Value}"); /*return true; */} ) ; //works!
          cvt["c#"].Select(p=> { WriteLine($"Select: key={p.Key} value={p.Value}"); return true; } ).ToList() ; // Why does this not work?
      }
    }

    • Marked as answer by siegfried_ Wednesday, January 23, 2019 12:38 AM
    Tuesday, January 22, 2019 11:04 PM
  • That fixes it!

    Why does that fix it?


    siegfried heintze

    Wednesday, January 23, 2019 12:39 AM
  • That fixes it!

    Why does that fix it?


    siegfried heintze

    It's lazy, that means it's loaded when it's needed. You can add an empty foreacht loop and it will work, too.

    Greetings, Chris

    Wednesday, January 23, 2019 5:52 PM
  • Or in your case you can trigger it like this:

    test.ElementAt(2);
    But why you want to use a select to write in console? The must programmer will not expect this. 

                cvt["c#"].ToList().ForEach(p =>
                {
                    Console.WriteLine($"Select: key={p.Key} value={p.Value}");
                });

    Wednesday, January 23, 2019 6:17 PM
  • When studying LINQ years ago, I remember reading that Microsoft intentionally did not implement the foreach statement and recommend we use select instead.

    Maybe this was the link?

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/e459a5f8-4027-4a1a-8f01-87799222a3e8/linq-equivalent-of-foreach?forum=csharpgeneral

    So this brings up a curious point: Microsoft says that they don't like a LINQ extension method ForEach (not to be confused with foreach) because it does not return a list value that can be pipelined into another operation. OK, I get it. But now I learn that if all I want is a side effect, (such as WriteLine) it does not work unless I call .ToList or .ElementAt…. Hmmm....

    Yeah-- I agree that my use of Select is less than intuitive and ForEach would be more intuitive. I was using Select because I thought it was the preferred function! Now I am not so sure...

    So what should I do? Use the System.Linq.Select with a .ToList() on the end or use my non-standard homegrown ForEach extension method?

    I don't like it when other programmers reinvent standard stuff (like homegrown XSLT packages). Homegrown stuff cannot be bing/google searched and typically needs more debugging.

    What do you think?

    Thanks

    Siegfried

    Thanks

    Siegfried


    siegfried heintze

    Wednesday, January 23, 2019 11:51 PM
  • Hi,

    I would use ToList().ForEach(x => ...). It is the Linq foreach.

    Greetings, Chris

    Thursday, January 24, 2019 1:18 AM