-
Notifications
You must be signed in to change notification settings - Fork 1
Improve error messaging around IQueryable<T> on open types #5
Description
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