Skip to content
This repository was archived by the owner on Feb 23, 2021. It is now read-only.
This repository was archived by the owner on Feb 23, 2021. It is now read-only.

Improve error messaging around IQueryable<T> on open types #5

@carusology

Description

@carusology

For one of my tests, I created an inner class of a base class with a generic type constraint. It looked something like this:

namespace Gambit.Authorization {
    public class RelatedRestrictedSiteRepositoryWrapperBaseTests<TUnitOfWork> {
        public class SiteRelatedFake {}
    }
}

When I attempted to use it as an IQueryable<Gambit.Authorization.RelatedRestrictedSiteRepositoryWrapperBaseTests<TUnitOfWork>.SiteRelatedFake>, I got the following stack trace:

Gambit.Authorization.RelatedRestrictedSiteRepositoryWrapperIntegrationTests.Queryable_Unrestricted [FAIL]
      System.ArgumentException : Method System.Linq.IQueryable`1[Gambit.Authorization.RelatedRestrictedSiteRepositoryWrapperBaseTests`1+SiteRelatedFake[TUnitOfWork]] nothing(System.Linq.IQueryable`1[Gambit.Authorization.RelatedRestrictedSiteRepositoryWrapperBaseTests`1+SiteRelatedFake[TUnitOfWork]]) contains generic parameters
      Parameter name: method
      Stack Trace:
           at System.Linq.Expressions.Expression.ValidateMethodInfo(MethodInfo method, String paramName)
           at System.Linq.Expressions.Expression.ValidateMethodAndGetParameters(Expression instance, MethodInfo method)
           at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression arg0)
           at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
           at FSharp.MySqlQueryProvider.Queryable.Query`1.getDefaultCallExpression()
           at FSharp.MySqlQueryProvider.Queryable.Query`1..ctor(QueryProvider provider, FSharpOption`1 expression)
        /Users/brian/invio/dev/gambit/src/Gambit.Persistence/MySqlRepository.cs(75,0): at Gambit.Persistence.MySqlRepository`1.BeginQueryable()
        /Users/brian/invio/dev/gambit/src/Gambit.Persistence/RepositoryBase.cs(53,0): at Gambit.Persistence.RepositoryBase`1.GetEnumerator()
        /Users/brian/invio/dev/gambit/src/Gambit.Persistence/RepositoryWrapper.cs(38,0): at Gambit.Persistence.RepositoryWrapper`1.GetEnumerator()
           at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
           at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
        /Users/brian/invio/dev/gambit/test/Gambit.Authorization.Tests/RelatedRestrictedSiteRepositoryWrapperBaseTests.cs(73,0): at Gambit.Authorization.RelatedRestrictedSiteRepositoryWrapperBaseTests`1.Queryable_Unrestricted()

Once I pulled the SiteRelatedFake class outside of the test class like I have shown below, the code worked fine, as I was now using IQueryable<Gambit.Authorization.SiteRelatedFake>.

namespace Gambit.Authorization {
    public class RelatedRestrictedSiteRepositoryWrapperBaseTests<TUnitOfWork> {}
    public class SiteRelatedFake {}
}

Ultimately, this error is happening because the T in IQueryable<T> is an open type (TUnitOfWork is not closed). I think it's fine if this is a limitation and cannot be supported, but I think the error messaging around it should be clearer of what's going on.

Looking around, it appears it is relatively simply to check for whether or not their are open types via the ContainsGenericParameters property on System.Type. Check out the following stack overflow threads for context:
https://stackoverflow.com/questions/25811514/detect-if-a-generic-type-is-open
https://stackoverflow.com/questions/13012733/difference-between-type-isgenerictypedefinition-and-type-containsgenericparamete

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions