Do not nest generic types in member signatures

c# expression-trees linq

Question

The following members are implemented by an extension class that violates the CA1006:DoNotNestGenericTypesInMemberSignatures rule by having signatures that are generic types.

Below is a copy of the code to which the warning relates.

How should the code be refactored to address the CA1006 warning?

Please note that although I am quite knowledgeable with anonymous methods, delegates, and lambdas, I am not particularly acquainted with expression trees.

Any assistance would be highly appreciated.

    public static DataServiceQuery<TElement> Expand<TElement, TPropType>(this DataServiceQuery<TElement> source, Expression<Func<TElement, TPropType>> propertySelector) 
    {
        string includeString = BuildString(propertySelector);
        return source.Expand(includeString);
    }

    private static string BuildString(Expression propertySelector)
    {
        switch (propertySelector.NodeType)
        {
            case ExpressionType.Lambda:
                LambdaExpression lambdaExpression = (LambdaExpression)propertySelector;
                return BuildString(lambdaExpression.Body);

            case ExpressionType.Quote:
                UnaryExpression unaryExpression = (UnaryExpression)propertySelector;
                return BuildString(unaryExpression.Operand);

            case ExpressionType.MemberAccess:

                MemberExpression memberExpression = (MemberExpression)propertySelector;
                MemberInfo propertyInfo = memberExpression.Member;

                if (memberExpression.Expression is ParameterExpression)
                {
                    return propertyInfo.Name;
                }
                else
                {
                    // we've got a nested property (e.g. MyType.SomeProperty.SomeNestedProperty)
                    return BuildString(memberExpression.Expression) + "/" + propertyInfo.Name;
                }

            case ExpressionType.Call:
                MethodCallExpression methodCallExpression = (MethodCallExpression)propertySelector;
                if (IsSubInclude(methodCallExpression.Method)) // check that it's a SubInclude call
                {
                    // argument 0 is the expression to which the SubInclude is applied (this could be member access or another SubInclude)
                    // argument 1 is the expression to apply to get the included property
                    // Pass both to BuildString to get the full expression
                    return BuildString(methodCallExpression.Arguments[0]) + "/" +
                           BuildString(methodCallExpression.Arguments[1]);
                }
                // else drop out and throw
                break;
        }
        throw new InvalidOperationException("Expression must be a member expression or an SubInclude call: " + propertySelector.ToString());

    }

    private static readonly MethodInfo[] SubIncludeMethods;
    static MyExtensions()
    {
        Type type = typeof(MyExtensions);
        SubIncludeMethods = type.GetMethods().Where(mi => mi.Name == "SubExpand").ToArray();
    }

    private static bool IsSubInclude(MethodInfo methodInfo)
    {
        if (methodInfo.IsGenericMethod)
        {
            if (!methodInfo.IsGenericMethodDefinition)
            {
                methodInfo = methodInfo.GetGenericMethodDefinition();
            }
        }
        return SubIncludeMethods.Contains(methodInfo);
    }

    public static TPropType SubExpand<TSource, TPropType>(this Collection<TSource> source, Expression<Func<TSource, TPropType>> propertySelector)
        where TSource : class
        where TPropType : class
    {
        throw new InvalidOperationException("This method is only intended for use with DataServiceQueryExtensions.Expand to generate expressions trees"); // no actually using this - just want the expression! 
    }

    public static TPropType SubExpand<TSource, TPropType>(this TSource source, Expression<Func<TSource, TPropType>> propertySelector)
        where TSource : class
        where TPropType : class
    {
        throw new InvalidOperationException("This method is only intended for use with DataServiceQueryExtensions.Expand to generate expressions trees"); // no actually using this - just want the expression! 
    }
1
3
2/18/2013 9:01:14 PM

Accepted Answer

The warning is a general caution meant to assist you in creating a more user-friendly and effective public interface. In this case you get a warning about having aExpression<Func<TElement, TPropType>> your method's argument. To silence the warning using a attribute or to delete the rule entirely from your ruleset, you should instead avoid simplifying the type for this function.


An absurd example where you should probably think about heeding the rule's recommendation is the following technique:

public void F(Dictionary<String, List<Tuple<String, Int32>>> dictionary);
8
2/18/2013 9:14:52 PM


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow