3

Hopefully someone could point out what I am doing wrong here. I have a process that reads in file access rules and I am trying to run it in Parallel.

Here is the code I have so far:

public List<FolderAccessRule> GetSecurityGroupsForFolder(long importId, string subdirectory, bool includeInherited)
    {
        ConcurrentQueue<FolderAccessRule> groups = new ConcurrentQueue<FolderAccessRule>();
        ConcurrentQueue<Exception> exceptions = new ConcurrentQueue<Exception>();

        DirectoryInfo dInfo = new DirectoryInfo(subdirectory);
        DirectorySecurity dSecurity = dInfo.GetAccessControl();

        AuthorizationRuleCollection authorizationRuleCollection = dSecurity.GetAccessRules(true, includeInherited, typeof(NTAccount));
        Parallel.ForEach( authorizationRuleCollection,
            fsar =>
            {
                try
                {
                    FolderAccessRule group = this.GetGroup(fsar);
                    if (group != null)
                    {
                        groups.Enqueue(group);
                    }
                }
                catch (Exception e)
                {
                    exceptions.Enqueue(e);
                }
            });

        foreach (Exception e in exceptions)
        {
            string message = string.Concat(e.GetType(), "Exception getting Directory info for  ", subdirectory);
            this.RecordException(message, subdirectory, e);
        }

        return groups.ToList();
    }

Which (to the untrained eye), looks like it should work. But the Parallel.ForEach will not compile as it gives the error:

The type arguments for method 'System.Threading.Tasks.Parallel.ForEach<TSource>
(System.Collections.Generic.IEnumerable<TSource>, System.Action<TSource>)' cannot be inferred from the usage.
Try specifying the type arguments explicitly.

I have also tried changing the offending line to:

Parallel.ForEach<FileSystemAccessRule>( authorizationRuleCollection, fsar =>

But still no joy.

So, what am I doing wrong? Thanks in advance.

Steve Hill
  • 2,331
  • 20
  • 27
Lobsterpants
  • 1,188
  • 2
  • 13
  • 33
  • Is that the only error? Uncomment code until it goes away. That tells you what's wrong. Post the reduced code. – usr Sep 21 '15 at 09:11

1 Answers1

5

Pass authorizationRuleCollection.OfType<AuthorizationRule>() to Parallel.ForEach, eg:

var typedColletion=authorizationRuleCollection.OfType<AuthorizationRule>();
Parallel.ForEach(typedColletion);

The error is caused because AuthorizationRuleCollection doesn't implement IEnumerable<T> but only IEnumerable, whose elements are Object. This is a common pattern with older (pre - .NET 2.0) collections, when generics weren't available.

Newer .NET classes return/expect generic collections. By calling OfType<T>() or Cast<T>() you effectively cast the source IEnumerable to an IEnumerable<T>.

The difference is that OfType<T>() will filter out incompatible elements, while Cast<T>() will throw if any incompatible elements are found.

The code behind both methods isn't magic, in the reference source it's simply an iterator over the source IEnumerable:

    public static IEnumerable<TResult> OfType<TResult>(this IEnumerable source) {
        if (source == null) throw Error.ArgumentNull("source");
        return OfTypeIterator<TResult>(source);
    }

    static IEnumerable<TResult> OfTypeIterator<TResult>(IEnumerable source) {
        foreach (object obj in source) {
            if (obj is TResult) yield return (TResult)obj;
        }
    }
Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236