Are there any good workarounds for FxCop warning CA1006?
Asked Answered
A

3

25

I am having trouble with FxCop warning CA1006, Microsoft.Design "DoNotNestGenericTypesInMemberSignatures". Specifically, I am designing a ReportCollection<T> class that inherits from ReadOnlyCollection<Report<T>>, and its public constructor takes an IList<Report<T>> as a parameter.

The suggestion for fixing this warning is not very useful:

"To fix a violation of this rule, change the design to remove the nested type argument." There are two ways I can see so far to change the design as suggested:

  1. Make the constructor internal. This doesn't work in my case. The constructor must be public because this collection class needs to be instantiable by code outside the assembly.
  2. Make the constructor take a Report<T>[] instead of an IList<Report<T>>. This is sub-optimal because external code should have the flexibility of using dynamically-sized data structures like List<T> instead of fixed-size arrays.

At this point, I have given up and suppressed this warning. Is there a better solution?

Armistice answered 6/1, 2009 at 18:29 Comment(0)
K
21

I agree, another good time to ignore this rule is when you need to say:

Func<IEnumerable<T>>

of course you could use the non-generic IEnumerable, but then any type can be used as long as it implements IEnumerable (non-generic). The purpose of generics (in part) is to restrict the types that are permisable to a given set of types.

I think this rule is very stupid. only need it if you have multiple generic types nested. one layer of nesting is more than safe.

BTW, I think a lot of the LINQ Functions nest generic types as well, so if MS does it, we can too :)

Kirstenkirsteni answered 23/11, 2010 at 4:9 Comment(1)
I wouldn't put any limit on the "safe" level of nesting. Generic types should be nested however deeply the semantics require. Limitations on interfaces' support for covariance and contravariance means that code which expects e.g. an IDictionary<string,IList<string>> won't be able to accept an IDictionary<string,List<string>>, but when nested generics are semantically correct I'd favor using them rather than trying to work around them.Hester
T
31

I would take FxCop's warnings as if they were suggestions from an extremely anal-retentive coworker. It's perfectly ok to ignore (suppress) some of the things it suggests.

Terebinthine answered 6/1, 2009 at 18:55 Comment(1)
+1 It is also a design warning, so sometimes these can really be classed as aesthetic especially if you are not designing a public API.Casimir
K
21

I agree, another good time to ignore this rule is when you need to say:

Func<IEnumerable<T>>

of course you could use the non-generic IEnumerable, but then any type can be used as long as it implements IEnumerable (non-generic). The purpose of generics (in part) is to restrict the types that are permisable to a given set of types.

I think this rule is very stupid. only need it if you have multiple generic types nested. one layer of nesting is more than safe.

BTW, I think a lot of the LINQ Functions nest generic types as well, so if MS does it, we can too :)

Kirstenkirsteni answered 23/11, 2010 at 4:9 Comment(1)
I wouldn't put any limit on the "safe" level of nesting. Generic types should be nested however deeply the semantics require. Limitations on interfaces' support for covariance and contravariance means that code which expects e.g. an IDictionary<string,IList<string>> won't be able to accept an IDictionary<string,List<string>>, but when nested generics are semantically correct I'd favor using them rather than trying to work around them.Hester
B
5

I agree that you can ignore the CA1006 warning in the case of

Func<IEnumerable<T>>

Also you can simplify your code by using delegates and avoid the CA1006:

public delegate IEnumerable<T> ChildrenDel<T>( T parent);

// was: GetDescendants<T>( this T item, Func< T, IEnumerable< T > > children )

public static IEnumerable< T > GetDescendants<T>( this T item, ChildrenDel<T> children )
{
    var stack = new Stack< T >();
    do {
        children( item ).ForEach( stack.Push );

        if( stack.Count == 0 )
            break;

        item = stack.Pop();

        yield return item;
    } while( true );
}
Beilul answered 14/10, 2015 at 11:45 Comment(1)
A problem with using delegates instead of Func<> is that Visual Studio won't give you a hint about the definition of a custom delegate in the same popup as the parent function signature - whereas Func is straightforward to infer a lambda for. Granted, this is an IDE issue rather than a language issue.Interchange

© 2022 - 2024 — McMap. All rights reserved.