Results 1 to 29 of 29

Thread: How to use Paralell.ForEach with a SearchResultCollection

  1. #1

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2006
    Posts
    746

    How to use Paralell.ForEach with a SearchResultCollection

    I can't seem to get the syntax right for a simple Parallel.Foreach Loop.

    This is how I would normally iterate a SearchResultCollection

    Code:
        Dim src As SearchResultCollection = DSearch.FindAll
            For Each x As SearchResult In src
                Debug.WriteLine(GetProperty(x, "Name"))
                'Parallel.ForEach(x, Function(x) Debug.WriteLine(x))
            Next
    As I have (obviously) misunderstood it this should be the syntax for the Parallel.Foreach

    Code:
    Parallel.ForEach(src, (Sub(x As SearchResult) GetProperty(x, "Name")))
    Parallel.ForEach(src, Function(x) Debug.WriteLine(x))
    It's not that though. What's the correct syntax here?
    ManagePC - the all-in-one PC management and inventory tool

  2. #2
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,532

    Re: How to use Paralell.ForEach with a SearchResultCollection

    well.... according to the documentation - http://msdn.microsoft.com/en-us/libr...0(VS.100).aspx

    ... this looks closest correct:
    Code:
    Parallel.ForEach(src, (Sub(x As SearchResult) GetProperty(x, "Name")))
    The only thing that looks off to me is a few extra parenthesis...and a missing end sub
    Code:
    Parallel.ForEach(src, Sub(x As SearchResult) 
                                       GetProperty(x, "Name")
                                 End Sub)
    -tg

    ADDENDUM - I noticed the example on MSDN didn't type the sub parameter... if that above doesn't work.. try this:
    Code:
    Parallel.ForEach(src, Sub(x) 
                                       GetProperty(x, "Name")
                                 End Sub)
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  3. #3

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2006
    Posts
    746

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Yeah, that's what I've been trying but I get

    Error 1 Overload resolution failed because no accessible 'ForEach' can be called with these arguments:
    'Public Shared Function ForEach(Of TSource)(source As System.Collections.Concurrent.OrderablePartitioner(Of TSource), body As System.Action(Of TSource, System.Threading.Tasks.ParallelLoopState, Long)) As System.Threading.Tasks.ParallelLoopResult': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
    'Public Shared Function ForEach(Of TSource)(source As System.Collections.Concurrent.Partitioner(Of TSource), body As System.Action(Of TSource, System.Threading.Tasks.ParallelLoopState)) As System.Threading.Tasks.ParallelLoopResult': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
    'Public Shared Function ForEach(Of TSource)(source As System.Collections.Concurrent.Partitioner(Of TSource), body As System.Action(Of TSource)) As System.Threading.Tasks.ParallelLoopResult': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
    'Public Shared Function ForEach(Of TSource)(source As System.Collections.Generic.IEnumerable(Of TSource), body As System.Action(Of TSource, System.Threading.Tasks.ParallelLoopState, Long)) As System.Threading.Tasks.ParallelLoopResult': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
    'Public Shared Function ForEach(Of TSource)(source As System.Collections.Generic.IEnumerable(Of TSource), body As System.Action(Of TSource, System.Threading.Tasks.ParallelLoopState)) As System.Threading.Tasks.ParallelLoopResult': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
    'Public Shared Function ForEach(Of TSource)(source As System.Collections.Generic.IEnumerable(Of TSource), body As System.Action(Of TSource)) As System.Threading.Tasks.ParallelLoopResult': Data type(s) of the type parameter(s) cannot be inferred from these arguments. Specifying the data type(s) explicitly might correct this error.
    ManagePC - the all-in-one PC management and inventory tool

  4. #4
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,532

    Re: How to use Paralell.ForEach with a SearchResultCollection

    What is "DSearch" ? I mean... what object type is it?

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  5. #5
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Quote Originally Posted by techgnome View Post
    What is "DSearch" ? I mean... what object type is it?

    -tg
    System.DirectoryServices.DirectorySearcher at a guess
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  6. #6
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,532

    Re: How to use Paralell.ForEach with a SearchResultCollection

    ah hah... I see ... it looks like the SearchResultCollection object returns more than one interface... the foreach can't figure out which one to follow (this is my guess...) ... Try using this:

    Code:
    Parallel.ForEach(src.GetEnumerator,
    If that still doesn't work, then odds are you've got something that isn't going to be compatible with the Parallel.ForEach. In which case, a good old fashioned For Each will have to suffice...
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  7. #7
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: How to use Paralell.ForEach with a SearchResultCollection

    I just had a quick look at this and I don't think its possible just using the result from the FindAll method directly because annoyingly you can't cast it to IEnumerable(Of SearchResult) or even ICollection(Of SearchResult) as you would have expected...
    The only way I can think of to get it to work is to just add each one of the results to a generic List and then pass the list in to the Parallel.ForEach like so:

    vb Code:
    1. Dim RawResults As SearchResultCollection = Searcher.FindAll
    2. Dim ResultsList As New List(Of SearchResult)
    3.  
    4. For Each Result As SearchResult In RawResults
    5.      ResultsList.Add(Result)
    6. Next
    7.  
    8. Parallel.ForEach(Of SearchResult)(ResultsList, AddressOf GetProperty)

    Then the GetProperty method signature is like this:
    vb Code:
    1. Private Sub GetProperty(ByVal Result As SearchResult, ByVal state As ParallelLoopState)
    2.     'Do whatever you want with the individual SearchResult objects here
    3. End Sub

    Not ideal but hopefully it helps

    EDIT: Already tried what you suggested TG but unfortunately that doesn't work either. The SearchResultCollection class is a rather annoying class to work with as I have discovered many times in the past...
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  8. #8
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,532

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Chris - I thought about that too... looping and putting it into a List... but the point of the Parallel.ForEach is that it does the looping for you. If you're going to loop through it anyways, might as well add the call to the sub in there too. Otherwise, I'm not sure you gain anything. (I could be wrong.)

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  9. #9
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Quote Originally Posted by techgnome View Post
    Chris - I thought about that too... looping and putting it into a List... but the point of the Parallel.ForEach is that it does the looping for you. If you're going to loop through it anyways, might as well add the call to the sub in there too. Otherwise, I'm not sure you gain anything. (I could be wrong.)

    -tg
    I think you definitely still gain something - the point of a loop isn't just to iterate through items in a collection is it, the point is to iterate through the collection and do something with each item in the collection. So in a parallel loop you gain the benefit of that action that you are doing to each item in the collection being performed simultaneously on its own thread without you having to create/manage the threads at all. So unless you were only doing something very trivial and fast with each item then you are bound to notice some performance benefits.
    Last edited by chris128; Oct 18th, 2010 at 03:58 PM.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  10. #10
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Oh and also if you want to make it look a little nicer (and also avoid repeating code if you need to do this in more than one place) then you can use an Extension method like this to add a "ToList" method onto the SearchResultCollection class:

    vb Code:
    1. Imports System.DirectoryServices
    2.  
    3. Module Extensions
    4.  
    5.     <Runtime.CompilerServices.Extension()> _
    6.     Public Function ToList(ByVal Instance As SearchResultCollection) As List(Of SearchResult)
    7.         Dim FinalList As New List(Of SearchResult)
    8.         For Each Result As SearchResult In Instance
    9.             FinalList.Add(Result)
    10.         Next
    11.         Return FinalList
    12.     End Function
    13.  
    14. End Module


    Then the previous example can be written like this:
    vb Code:
    1. Dim RawResults As SearchResultCollection = Searcher.FindAll
    2.  
    3. Parallel.ForEach(Of SearchResult)(RawResults.ToList, AddressOf GetProperty)
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  11. #11

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2006
    Posts
    746

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Yup. That worked. Unfortunately, it didn't provide a performance improvement over a normal ForEach.

    Oh well. Worth a try
    ManagePC - the all-in-one PC management and inventory tool

  12. #12
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Yeah well like I said it depends what you were actually doing with each item in your GetProperty method
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  13. #13

    Thread Starter
    Fanatic Member
    Join Date
    Apr 2006
    Posts
    746

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Oh, nothing special. It just returned a value from a searchresult property. I was merely intrigued in testing the performance improvements of the new parallel features of .NET 4.0
    ManagePC - the all-in-one PC management and inventory tool

  14. #14
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,532

    Re: How to use Paralell.ForEach with a SearchResultCollection

    What is your system specs? Processors, Cores, OS? Each of those will impact the performance as well.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  15. #15
    New Member
    Join Date
    May 2005
    Posts
    9

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Quote Originally Posted by chris128 View Post
    vb Code:
    1. Dim RawResults As SearchResultCollection = Searcher.FindAll
    2. Dim ResultsList As New List(Of SearchResult)
    3.  
    4. For Each Result As SearchResult In RawResults
    5.      ResultsList.Add(Result)
    6. Next
    7.  
    8. Parallel.ForEach(Of SearchResult)(ResultsList, AddressOf GetProperty)
    Why are you creating a SearchResultCollection only to convert it to a collection of SearchResult? Seems a bit redundant and over worked. If you're going to loop through everything then you might as well just make it a basic object list since the default for Parallel is object based.

    In this example I'll be going through a domain to find all machines:

    Code:
    Dim dsDomain As System.DirectoryServices.DirectoryEntry = New System.DirectoryServices.DirectoryEntry("LDAP://DC=domain,DC=com")
    Dim dsSearcher As System.DirectoryServices.DirectorySearcher = New System.DirectoryServices.DirectorySearcher(dsDomain)
    dsSearcher.Filter = ("(objectClass=computer)")
    
    Dim results As New List(Of Object)
    
    For Each machine In dsSearcher.FindAll()
        results.Add(Mid(machine.GetDirectoryEntry().Name.ToString(), 4))
    Next
    
    Parallel.ForEach(results, _
    	Sub(machine)
    
    	End Sub)
    No second method needed and no more conversions.

  16. #16
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Quote Originally Posted by JEmlay View Post
    Why are you creating a SearchResultCollection only to convert it to a collection of SearchResult?
    Because you have no choice in creating a SearchResultCollection - that is what the FindAll method returns. You can't do a Parallel For Each through that though, which is exactly why the OP posted this question. So my "solution" is to add each result from the SearchResultCollection to a generic List(Of T), which you then can do a Parallel For Each through.

    If you're going to loop through everything then you might as well just make it a basic object list since the default for Parallel is object based.
    How is that any better? It doesn't cost anything more to create a List(Of SearchResult) than it does to create a List(Of Object) and at least with the List(Of SearchResult) it is strongly typed. I don't understand the argument for using Object instead of a specific class when you know that class is the only type of object you will be adding to that list. As far as I can see there is absolutely no benefit to using Object, whereas there are benefits to actually specifying a type. By your logic, we should just use Object for everything right? Why bother with types at all...

    No second method needed and no more conversions.
    The second method wasn't "needed" at all (assuming you're referring to the extension method I mentioned) and I didn't even include it in the original post that you quoted. Like I said, that is just to make it look nicer and be slightly more convenient to use. Also I'm not sure what conversions you're referring to. Nowhere in my code am I converting anything - if you're referring to adding each item from the SearchResultCollection to a List(Of SearchResult), you're doing the exact same thing in your code but "converting" to a List(Of Object) which as explained above is worse if anything.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  17. #17
    New Member
    Join Date
    May 2005
    Posts
    9

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Quote Originally Posted by chris128 View Post
    Because you have no choice in creating a SearchResultCollection - that is what the FindAll method returns. You can't do a Parallel For Each through that though, which is exactly why the OP posted this question.
    You didn't understand what I asked.

    Quote Originally Posted by chris128 View Post
    How is that any better? It doesn't cost anything more to create a List(Of SearchResult) than it does to create a List(Of Object)
    Yes it does. It cost you your addition sub. You're passing it along yet again. That's completely not needed.

    "Private Sub GetProperty'

    Not to mention an overly complex call because of it:

    Parallel.ForEach(Of SearchResult)(ResultsList, AddressOf GetProperty)

    versus

    Parallel.ForEach(results, Sub(machine)

    If you're going to convert SearchResultCollection FOR PARALLEL then you might as well convert it to the default input for Parallell....now I'm just repeating myself.

  18. #18
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: How to use Paralell.ForEach with a SearchResultCollection

    That's not actually any different at all... you're just writing the method in line rather than as a separate method. Its still the exact same thing that is happening.

    Why does converting it so that it fits the default overload of the Parallel For Each make it any better? The default overload is not any "better" than another overload, its just different and used for different circumstances.

    In your example you're going to have to convert/cast that Object back to a strongly typed class in your in line Sub anyway (unless you've got Option Strict turned off and are allowing late binding, which a million people on here will tell you is not a good idea), so you're not gaining anything at all. All you are doing is moving the point that you do the casting.

    Your example:
    Loop through SearchResultCollection and add each SearchResult to a list as an Object.
    Pass in items to the in line method as an Object.
    Method has to cast them to a SearchResult to be able to use them.

    My example:
    Loop through SearchResultCollection and add each SearchResult to a list as a SearchResult.
    Pass in items to a separate method as a SearchResult.
    Method can use them directly.

    Can't you see that you're not gaining anything at all?
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  19. #19
    New Member
    Join Date
    May 2005
    Posts
    9

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Quote Originally Posted by chris128 View Post
    That's not actually any different at all... you're just writing the method in line rather than as a separate method. Its still the exact same thing that is happening.
    You seem to be turning a blind eye to the fact that you are creating additional work.

    "Yes it does. It cost you your addition sub. You're passing it along YET AGAIN. That's completely not needed."

    Quote Originally Posted by chris128 View Post
    Why does converting it so that it fits the default overload of the Parallel For Each make it any better?
    Less work.

    Quote Originally Posted by chris128 View Post
    In your example you're going to have to convert/cast that Object back to a strongly typed class in your in line Sub anyway
    No, I'm not. How do you figure? The work performed in the ForEach is the end result. Even if you did need to go back BOTH OF THEM EXIST if you need them to.

    Quote Originally Posted by chris128 View Post
    Method has to cast them to a SearchResult to be able to use them.
    No, it doesn't.

    Simplified code is simplified code. If you want to throw in unneeded extra routines then knock yourself out. I simply provided a more logical and slimmed down way about it for others who find themselves here as I did. I really don't care if you don't like it. It's for others to use.

  20. #20
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: How to use Paralell.ForEach with a SearchResultCollection

    lol so you base the code you use on how easy it is to write rather than how well it performs or how reliable it is? I agree you shouldn't make things overly complex if it can be avoided but in this case I don't think anything here is overly complex and I think it is the best option to use for those of us with Option Strict on (which is almost everyone... but from your code example I can see you don't have it on, which is probably why you are oblivious to the type casting I'm referring to). I still don't see how you think writing Sub/End Sub in line is any less work than writing it as a separate method - you still type the same characters, just in a different place.

    Yes it does. It cost you your addition sub. You're passing it along YET AGAIN. That's completely not needed
    Like I already explained, that additional sub is getting generated either way. You're passing the object on to an additional sub either way - all you're doing is writing that sub in line rather than separately. The EXACT same thing is still happening either way though. Don't believe me? Here's my example method and the resulting code in Reflector after it has been compiled:

    vb.net Code:
    1. Imports System.DirectoryServices
    2. Imports System.Threading.Tasks
    3.  
    4. Public Class Mine
    5.  
    6.     Private Sub Example()
    7.         Dim Searcher As New DirectorySearcher
    8.         Dim RawResults As SearchResultCollection = Searcher.FindAll
    9.         Dim ResultsList As New List(Of SearchResult)
    10.  
    11.         For Each Result As SearchResult In RawResults
    12.             ResultsList.Add(Result)
    13.         Next
    14.  
    15.         Parallel.ForEach(Of SearchResult)(ResultsList, AddressOf GetProperty)
    16.  
    17.     End Sub
    18.  
    19.     Private Sub GetProperty(ByVal Result As SearchResult, ByVal state As ParallelLoopState)
    20.         IO.File.WriteAllText("C:\example.txt", Result.Path)
    21.     End Sub
    22.  
    23. End Class

    Name:  mine.jpg
Views: 2514
Size:  21.1 KB

    and here's an example of yours:

    vb.net Code:
    1. Imports System.DirectoryServices
    2. Imports System.Threading.Tasks
    3.  
    4. Public Class Yours
    5.  
    6.     Private Sub Example()
    7.         Dim Searcher As New DirectorySearcher
    8.         Dim RawResults As SearchResultCollection = Searcher.FindAll
    9.         Dim ResultsList As New List(Of Object)
    10.  
    11.         For Each Result As SearchResult In RawResults
    12.             ResultsList.Add(Result)
    13.         Next
    14.  
    15.         Parallel.ForEach(ResultsList, Sub(Machine)
    16.                                           IO.File.WriteAllText("C:\example.txt", DirectCast(Machine, SearchResult).Path)
    17.                                       End Sub)
    18.  
    19.     End Sub
    20.  
    21. End Class

    Name:  Yours.jpg
Views: 2733
Size:  29.1 KB

    See how a separate sub is still being created in your example even though it was written "in line" in the actual source code? The only difference is the compiler created your extra sub and named it Lamda$_1. Also see how I have to cast the object to a SearchResult to be able to use it? If I don't do that then it won't even compile with Option Strict turned on. Turn it on (as you should anyway) and you'll see what I mean.
    Last edited by chris128; Mar 17th, 2014 at 01:22 PM.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  21. #21
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Quote Originally Posted by JEmlay View Post
    I simply provided a more logical and slimmed down way about it for others who find themselves here as I did. I really don't care if you don't like it. It's for others to use.
    That's fair enough but you didn't just provide a slimmed down version - you specifically asked why I did it the way I did:

    "Why are you creating a SearchResultCollection only to convert it to a collection of SearchResult?"
    Which is why I answered explaining why I did it that way and not your way. Your example won't even compile for anyone with Option Strict turned on, but yes if you have it turned off and don't care about doing things the best way, just want the simplest method possible with the least amount of typing then your method is fine.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  22. #22
    New Member
    Join Date
    May 2005
    Posts
    9

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Quote Originally Posted by chris128 View Post
    That's fair enough but you didn't just provide a slimmed down version - you specifically asked why I did it the way I did:
    http://tinyurl.com/d36gu3q

    Quote Originally Posted by chris128 View Post
    Your example won't even compile for anyone with Option Strict turned on, but yes if you have it turned off and don't care about doing things the best way, just want the simplest method possible with the least amount of typing then your method is fine.
    That's BS and I wont even get into a debate over that. Countless examples of Microsoft's own code wont even compile with it turned on which is why people kill themselves over such ridiculous debates.

  23. #23
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: How to use Paralell.ForEach with a SearchResultCollection

    I've had option strict turned on for the last 3 years at least and never had an issue, and I know most people on these forums have it turned on as well. There have been many threads about it. It simply encourages better programming and in some cases also improved performance and helps avoid potential bugs.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


  24. #24

    Re: How to use Paralell.ForEach with a SearchResultCollection

    This...might seem a little silly due to the original OP's post but...

    Code:
    Dim src As SearchResultCollection = DSearch.FindAll
    For Each x As SearchResult In src
        Debug.WriteLine(GetProperty(x, "Name"))
        'Parallel.ForEach(x, Function(x) Debug.WriteLine(x))
    Next
    Couldn't you just...do this?

    Code:
    Dim src As IEnumerable(Of SearchResult) = DSearch.FindAll().Cast(Of SearchResult)

  25. #25
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    34,532

    Re: How to use Paralell.ForEach with a SearchResultCollection

    considering the thread was 3 1/2 years old, it seems even more silly.

    -tg
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  26. #26

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Quote Originally Posted by techgnome View Post
    considering the thread was 3 1/2 years old, it seems even more silly.

    -tg
    I think it's more sad I didn't realize the thread was that old.

  27. #27
    New Member
    Join Date
    May 2005
    Posts
    9

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Quote Originally Posted by formlesstree4 View Post
    Couldn't you just...do this?

    Code:
    Dim src As IEnumerable(Of SearchResult) = DSearch.FindAll().Cast(Of SearchResult)
    Nope, can't cast a system COM object to IDirectorySearch. IEnumerable is pretty much out the window.

  28. #28

    Re: How to use Paralell.ForEach with a SearchResultCollection

    Quote Originally Posted by JEmlay View Post
    Nope, can't cast a system COM object to IDirectorySearch. IEnumerable is pretty much out the window.
    According to the class declaration of FindAll, it returns a SearchResultCollection which is decorated as followed:
    Code:
    public class SearchResultCollection : MarshalByRefObject, ICollection, IEnumerable, IDisposable
    So, since it implements IEnumerable, in theory, we should be able to enumerate through the collection since the value is a SearchResult class. Inside SearchResultCollection, we do see the indexer declared as such:
    Code:
    public SearchResult this[int index] { get; }
    So far so good.

    Now, Cast is declared in Enumerable.cs as such:
    Code:
    public static IEnumerable<TResult> Cast<TResult>(this IEnumerable source) {
                IEnumerable<TResult> typedSource = source as IEnumerable<TResult>;
                if (typedSource != null) return typedSource;
                if (source == null) throw Error.ArgumentNull("source");
                return CastIterator<TResult>(source);
            }
    I know I know, what the heck-fire is CastIterator? Well, it's defined as such:

    Code:
    static IEnumerable<TResult> CastIterator<TResult>(IEnumerable source) {
                foreach (object obj in source) yield return (TResult)obj;
            }
    Is this not the same as the original OP's code of:
    Code:
    For Each x As SearchResult In src
    Just merely doing boxing (casting to Object) and unboxing (casting back to SearchResult)?

    Perhaps the code may not work, however IDirectorySearch being there or not doesn't seem to matter. The class SearchResultCollection implements IEnumerable, which is more than enough to qualify it for Cast<T> and Cast<T> does a foreach on the SearchResultCollection (which is valid; IEnumerable is there as well as ICollection and if we really wanted to see, C# supports pattern matching for the foreach construct so we could even get away with not having IEnumerable [in special circumstances where GetEnumerator must exist and the return value of GetEnumerator must contain two properties: MoveNext() and Current; MoveNext() is a Boolean while Current returns an object]) which merely returns the object in a collection as they are pulled.


    Following this, let's test the logic out, shall we?

    Code:
                var oSearcher = new System.DirectoryServices.DirectorySearcher();
                var oResults = oSearcher.FindAll().Cast<System.DirectoryServices.SearchResult>();
                foreach (System.DirectoryServices.SearchResult oResult in oResults)
                    Console.WriteLine(oResult.Path);
                Console.ReadLine();
    This code compiles and runs in VS2012 running on .NET 4.0, and in fact does loop through correctly.


    EDIT: Here's a test class to throw into a foreach loop in C# (Does not work in VB.net, but since all the base .NET framework code is C#, this sample is valid for the sake of argument):
    Code:
    class Foo
        {
            public Bar GetEnumerator() { return new Bar(); }
            public struct Bar
            {
                public bool MoveNext()
                {
                    return false;
                }
    
                public object Current
                {
                    get { return null; }
                }
            }
        }
    
    // The following will compile
    var z = new Foo();
                foreach (var item in z)
                {
                    
                }
    Last edited by formlesstree4; Mar 17th, 2014 at 06:00 PM. Reason: Clarifying the pattern matching constraint

  29. #29
    Pro Grammar chris128's Avatar
    Join Date
    Jun 2007
    Location
    England
    Posts
    7,604

    Re: How to use Paralell.ForEach with a SearchResultCollection

    I didn't know about that Cast extension method but yeah that is better than my extension method in post #10 as it doesn't need to create a new list at all. So you're right, the simplest way would be something like this:

    vb.net Code:
    1. Private Sub Example()
    2.         Dim Searcher As New DirectorySearcher
    3.  
    4.         Dim src As IEnumerable(Of SearchResult) = Searcher.FindAll().Cast(Of SearchResult)()
    5.         Parallel.ForEach(src, AddressOf test)
    6.  
    7.     End Sub
    8.  
    9.     Private Sub test(Result As SearchResult)
    10.         MessageBox.Show(Result.Path)
    11.     End Sub

    or in line because its "less work" lol

    vb.net Code:
    1. Private Sub Example()
    2.         Dim Searcher As New DirectorySearcher
    3.  
    4.         Dim src As IEnumerable(Of SearchResult) = Searcher.FindAll().Cast(Of SearchResult)()
    5.         Parallel.ForEach(src, Sub(Result As SearchResult)
    6.                                   MessageBox.Show(Result.Path)
    7.                               End Sub)
    8.  
    9.     End Sub

    Thanks for the heads up on the Cast extension method - I'm sure that will come in handy in future
    Last edited by chris128; Mar 17th, 2014 at 07:09 PM.
    My free .NET Windows API library (Version 2.2 Released 12/06/2011)

    Blog: cjwdev.wordpress.com
    Web: www.cjwdev.co.uk


Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width