1

My application's business-logic layer performs its own authorization checks and all data-querying operations return a GuardedResult<TResult> value, here's the definition:

public class GuardedResult<TResult> {
    public TResult Result { get; }
    public Status Status { get; }
    public GuardedResult(TResult result, Status status) {
        this.Result = result;
        this.Status = status;
    }
    public static implicit operator GuardedResult<TResult>(TResult result) {
        return new GuardedResult<TResult>(result, Status.Success);
    }
}

Used like so:

public partial class EmployeesBusinessLogic {

    public GuardedResult<Employee> GetEmployee(Int64 employeeId) {

        if( this.CurrentUser.CanReadAll ) {

            return this.Data.Employees.GetEmployeeById( employeeId );

        }
        else if( this.CurrentUser.CanReadSelf ) {

            if( this.CurrentUser.EmployeeId == employeeId ) {

                return this.Data.Employees.GetEmployeeById( employeeId );
            }
            else {

                return new GuardedResult<Employee>( null, Status.AccessDenied );
            }
        }
        else {
            return new GuardedResult<Employee>( null, Status.AccessDenied );
        }
    }
}

This builds and works fine.

However when I change TResult to a closed-generic IQueryable it fails:

public GuardedResult<IQueryable<Employee>> GetEmployees() {

    if( this.CurrentUser.CanReadAll ) {

        return this.Data.Employees.GetAllEmployees();
    }
    else {

        return new GuardedResult<IQueryable<Employee>>( null, Status.AccessDenied );
    }
}

The compiler error is:

Error CS0266
Cannot implicitly convert type 'System.Linq.IQueryable<Initech.Employee>' to 'Initech.GuardedResult<System.Linq.IQueryable<Initech.Employee>>'.
An explicit conversion exists (are you missing a cast?)

Here is the the relevant definitions from the EmployeesData class:

public IQueryable<Employee> GetAllEmployees() {
    return this.dbContext.Employees;
}

public Employee GetEmployeeById(Int64 employeeId) {
    return this.dbContext.Employees.SingleOrDefault( e => e.EmployeeId == employeeId );
}
Dai
  • 141,631
  • 28
  • 261
  • 374
  • `return this.Data.Employees.GetAllEmployees();` I believe this is the line which causes the problem – or hor May 02 '16 at 10:45
  • What does `GetAllEmployees` return? It's not used in the "code that works"? – Jcl May 02 '16 at 10:47
  • @orhor I have amended my posting with the definition of the 'GetAllEmployees` method. – Dai May 02 '16 at 10:57
  • @jcl it returns an `IQueryable`, the same type as declared in the business layer. I have amended my posting with the details. – Dai May 02 '16 at 10:58
  • @Dai, You need to return `GuardedResult>` and not `IQuerable`, e.g. `return new GuardedResult>( this.Data.Employees.GetAllEmployees(), Status.AccessDenied );` – Chris Wohlert May 02 '16 at 11:04
  • 1
    @Dai, yeah, I could have guessed if I had read the question better... tough luck, implicit casting won't work for you... check [this question](http://stackoverflow.com/questions/1208796/c-sharp-compiler-bug-why-doesnt-this-implicit-user-defined-conversion-compile) specifically the accepted answer and the one below by Eric Lippert – Jcl May 02 '16 at 11:05
  • @ChrisWohlert he obviously wanted the implicit casting operator to work :-) – Jcl May 02 '16 at 11:05
  • @Jcl, Oh yeah, sorry, might've been too quick there. :) – Chris Wohlert May 02 '16 at 11:06
  • as I stated, your `GetEmployees()` returns `GuardedResult>`, but `GetAllEmployees()` returns `IQueryable`. This is something that needs to be corrected. You have this line: `return this.Data.Employees.GetAllEmployees();` which is most probably uncompileable. – or hor May 02 '16 at 11:36
  • @orhor Please read my question fully. I'm trying to make use of C#'s `implicit` type conversion capabilities. – Dai May 02 '16 at 21:18

1 Answers1

1

I know I'm not answering what you want here, but as it turns out, the implicit casting operator won't work in your case (and although confusingly, the why is in the specs, but don't let me try to make sense of it, and see the answer for why)

Then again, for your specific case, it'd be a matter of doing:

return new GuardedResult<IQueryable<Employee>>(
          this.Data.Employees.GetAllEmployees(), Status.Success);

Again, more likely not what you wanted to hear

Community
  • 1
  • 1
Jcl
  • 27,696
  • 5
  • 61
  • 92
  • At least I can save on typing by wrapping the constructor call in an abbreviated function. – Dai May 02 '16 at 21:21