Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / C# / March 2008

Tip: Looking for answers? Try searching our database.

Linq oddity?

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Chris Dunaway - 12 Mar 2008 21:20 GMT
The following code is placed a new Windows Forms App and a
DataGridView and BindingSource are dragged onto the form:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ThrowAwayCS
{
   public partial class Form1 : Form
   {
       public Form1()
       {
           InitializeComponent();
       }

       protected override void OnShown(EventArgs e)
       {
           base.OnShown(e);

           dataGridView1.AutoGenerateColumns = true;
           dataGridView1.DataSource = bindingSource1;

           var procs = from process in
System.Diagnostics.Process.GetProcesses()
                       select process.ProcessName;

           bindingSource1.DataSource = procs;
       }
   }
}

When run, the grid does not show a ProcessName column with the names
of the processes as expected, it has a Length column with the lengths
of the names.

However, change the LINQ to the following and the correct values are
shown:

           var procs = from process in
System.Diagnostics.Process.GetProcesses()
                       select new {process.ProcessName};

Can anyone shed some light on this?  I am sure I am missing something
obvious.

Thanks,

Chris
Jon Skeet [C# MVP] - 12 Mar 2008 21:54 GMT
<snip>

> When run, the grid does not show a ProcessName column with the names
> of the processes as expected, it has a Length column with the lengths
[quoted text clipped - 9 lines]
> Can anyone shed some light on this?  I am sure I am missing something
> obvious.

First version:
Type of data is a string, only public property is Length

Second version:
Type of data is an anonymous type, public property is ProcessName

I'm guessing that a BindingSource looks through the properties of the
type of data that's provided to it, and displays those. You basically
want to display the whole item, giving a column of "Process Name", I
suspect.

I'm afraid I don't know enough about how data binding is meant to work,
but I suspect the above explains your results to some extent :)

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
World class .NET training in the UK: http://iterativetraining.co.uk

Chris Dunaway - 13 Mar 2008 18:11 GMT
     var procs = from process in
System.Diagnostics.Process.GetProcesses()
                      select process.ProcessName;

Ok, continuing the discussion, using the query above as a start, what
is procs after I'm done?  Is it an IEnumerable<string>?  Secondly, how
would I select processes with a unique name?

I tried this:

   var uniqueProcs =
System.Diagnostics.Process.GetProcesses().SelectMany(p =>
p.ProcessName).Distinct();

But that doesn't produce what I thought.

Finally, why didn't the C# team include all the query operators like
the VB team did?  I hope they will be included in the future.

Thanks,

Chris
Jon Skeet [C# MVP] - 13 Mar 2008 18:27 GMT
>       var procs = from process in
> System.Diagnostics.Process.GetProcesses()
>                        select process.ProcessName;
>
> Ok, continuing the discussion, using the query above as a start, what
> is procs after I'm done?  Is it an IEnumerable<string>?  

Yes, that's an IEnumerable<string>. Hover over "var" to see what type
the compiler has inferred.

> Secondly, how would I select processes with a unique name?

Do you mean select a distinct set of process names?

var uniqueProcs = Process.GetProcesses()
                        .Select(proc => proc.ProcessName)
                        .Distinct();

> I tried this:
>
[quoted text clipped - 3 lines]
>
> But that doesn't produce what I thought.

Hmm... I suspect that gave you back a distinct sequence of all the
*characters* which are in any of the processes.

SelectMany takes each element of the original sequence and generates a
subsequence *per element*. The overload you've used just flattens that
resulting subsequence. Now, the delegate you've used to convert an
original element (Process) to a subsequence is to take the process name
- which is a string, i.e. a sequence of characters.

> Finally, why didn't the C# team include all the query operators like
> the VB team did?  I hope they will be included in the future.

I hope they won't. I like a simple language with a big library behind
it. The existing query expressions already complicate the language, but
they cover the biggest uses. Calling methods explicitly when they don't
cover it is reasonable to me - but adding yet more complexity to the
language would be a mistake IMO.

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
World class .NET training in the UK: http://iterativetraining.co.uk

Chris Dunaway - 13 Mar 2008 18:54 GMT
> Do you mean select a distinct set of process names?
>
> var uniqueProcs = Process.GetProcesses()
>                          .Select(proc => proc.ProcessName)
>                          .Distinct();

Thanks, here's what I ended up with and it returned the results I
expected.  However, curiously, the VB version did not seem to work:

C# version works (new keyword used so data binding will work
correctly):

           var uniqueProcs = Process.GetProcesses()
                             .OrderBy(p => p.ProcessName)
                             .Select(p => new { p.ProcessName })
                             .Distinct();

VB version doesn't work (New keyword used so data binding will work
correctly):

       Dim uniqueProcs = Process.GetProcesses() _
                   .OrderBy(Function(p) p.ProcessName) _
                   .Select(Function(p) New With {p.ProcessName}) _
                   .Distinct()

And when I say it doesn't work, I mean that it returns a list, but the
duplicates are not removed.

> > Finally, why didn't the C# team include all the query operators like
> > the VB team did?  I hope they will be included in the future.
[quoted text clipped - 4 lines]
> cover it is reasonable to me - but adding yet more complexity to the
> language would be a mistake IMO.

I agree, but I still think having at least distinct, skip, and take
would be nice.

An expression like this seems a little nicer than using the extension
methods with lambdas, not that the latter is too difficult to read
though.

           //Non working code
           var procs = from process in Process.GetProcesses()
                            orderby process.ProcessName
                            select new { process.ProcessName }
                            distinct;

Cheers,

Chris
Jon Skeet [C# MVP] - 13 Mar 2008 20:30 GMT
> > Do you mean select a distinct set of process names?
> >
[quoted text clipped - 23 lines]
> And when I say it doesn't work, I mean that it returns a list, but the
> duplicates are not removed.

This is because by default, VB anonymous types are mutable. Change it
to
New With { Key p.Processname }
and I think you'll find it's okay.

Frankly I find this choice a bizarre one on the part of the VB team.
The rest of the world is running towards immutability, and VB decides
to default to mutability...

> > > Finally, why didn't the C# team include all the query operators like
> > > the VB team did?  I hope they will be included in the future.
[quoted text clipped - 17 lines]
>                              select new { process.ProcessName }
>                              distinct;

I don't think that's much better than:

            var procs = (from process in Process.GetProcesses()
                             orderby process.ProcessName
                             select new { process.ProcessName })
                         .Distinct();

The difference is a mere 5 characters - not a lot compared with the
complexity cost to the language. Note that the existing query
expression clauses all save redundancy in terms of expressing a lambda
expression.

I guess we'll have to agree to differ though.

Signature

Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet   Blog: http://www.msmvps.com/jon.skeet
World class .NET training in the UK: http://iterativetraining.co.uk


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.