简体   繁体   中英

C# Refactoring - How to pass generic method with possibly multiple parameters?

I have business object classes with several methods that typically follows the pattern:

  • always return an object Result
  • test a boolean pre-condition: IsAllowed (to check for instance if someone can do something (MyAction enum) at a given context (MyContext enum).
  • if the test passes then do something (typically at the database level returning a Result object) otherwise return PermissionDenied() which returns a Result (a simple object with a boolean result set as false and other properties including error messages).

Example:

protected MyContext Context;
protected MyAction Action;

public Result List1(int p1, int p2, int p3, object p4, string p5)
    => IsAllowed(MyContext.Page, MyAction.List) ? DB.List1(p1, p2, p3, p4, p5) : PermissionDenied();

public Result View2(int p1, int p2)
    => IsAllowed(this.Context, this.Action) ? DB.View2(p1, p2) : PermissionDenied();

public Result Edit3(int p1, string p2)
    => IsAllowed(MyContext.Document, MyAction.Edit) ? DB.Edit3(p1, p2) : PermissionDenied();

(...)

I'd like guidance on how to improve and simplify this pattern by having a method that could handle that grant condition. I imagine something like GrantDo() , but how can that method handle/receive the inner method, represented here as ??? what

Public Result GrantDo(??? what, MyContext? ctx=null, MyAction? act=null){
    if (IsAllowed(ctx == null ? this.Context : ctx, act == null ? this.Action : act))
        return what();    
    else
        return PermissionDenied();
}

That way, I imagine the above methods could be re-written like:

public Result List1(int p1, int p2, int p3, object p4, string p5)
    => GrantDo(DB.List1(p1, p2, p3, p4, p5), MyContext.Page, MyAction.List);

public Result View2(int p1, int p2) => GrantDo(DB.View2(p1, p2));

(...)

Thank you for any suggestion and ideas.

You just need to pass a function ( an Action a Func) and you can simplify the null checks:

public Result GrantDo(Func<Result> action, MyContext? ctx = null, MyAction? act = null) =>
    IsAllowed(context ?? this.Context, act ?? this.Action) 
        ? action() 
        : PermissionDenied();

I finally got this working solution (thank you for your guidance @Alvin).

public Result GrantDo(Func<Result> method, MyAction action, MyContext? context = null)
=> IsAllowed(context ?? Context, action) ? method() : PermissionDenied();

Found more info about the distinct concepts:

Action is a delegate (pointer) to a method, that takes zero, one or more input parameters, but does not return anything.

Func is a delegate (pointer) to a method, that takes zero, one or more input parameters, and returns a value (or reference).

Predicate is a special kind of Func often used for comparisons.

source: Func vs. Action vs. Predicate

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM