Casting/Mapping Delegates

2019-06-12 22:09发布

问题:

I have a method

  public List<DTO.User> GetUsers(Func<Domain.User, bool> expression)
  {
        var users = new List<DTO.User>();

        using(UserContext context = new UserContext())
        {
           // obviously an error
           users = context.Users.ToList();
        }

        return users;

   }

Notice the DTO.User (a DTO) and Domain.User (a domain entity from EF) So I use AutoMapper to map entities like this

  public List<DTO.User> GetUsers()
  {
        var users = new List<DTO.User>();

        using(UserContext context = new UserContext())
        {

           Mapper.CreateMap<Domain.User, DTO.User>();
           users = 
           Mapper.Map<List<Domain.User>,List<DTO.User>>(context.Users.ToList());
        }

       return users;

   }

Alright, this looks OK but.. I want the GetUser method to accept a delegate expression as a parameter. I have a grid in the ui that displays the user list and it has many filtering options, so I want my UI to just call 1 method instead of creating method per filter.

  // filter by username
  List<DTO.User> users = userBL.GetUsers(u => u.UserName.Contains(txtUserName.Text));

  // filter by ID
  List<DTO.User> users = userBL.GetUsers(u => u.== txtUserID.Text);

  ...

So I came up with the Idea like this in my DAL layer

  public List<DTO.User> GetUsers(Func<DTO.User, bool> expression)
  {
        var users = new List<DTO.User>();

        using(UserContext context = new UserContext())
        {
           Mapper.CreateMap<Domain.User, DTO.User>();

           Func<Domain.User, bool> predicate;

           // this is an error on AutoMaper
           predicate = Mapper.Map<Func<DTO.User,bool>, Func<Domain.User, bool>>(expression)

           // I also tried direct casting which is an obvious fail
           //predicate = (Func<Domain.User,bool>)expression;

           users = 
           Mapper.Map<Domain.User, DTO.User>(context.Users.Where(predicate).ToList());
        }

       return users;

   }

So basically, I'm trying to cast or map the DTO delegate to Domain delaget for it to be use in the .Where() method of the domain.User list. Is it possible? thanks in advance.

回答1:

I'm almost sure that you cannot map delegate to another delegate but your code has even more problems:

  • If you pass Func<User, bool> to your Linq-to-entities query you will do the same as you do now. It will pull all data from the database and execute filter in your application server's memory. You must pass Expression<Func<User, bool>> to execute it on DB server.
  • I don't know whole your architecture and complexity of the application but I feel that placing conversion to DTOs directly in DAL is not good. I can imagine doing this only in EFv1 when using EntityObjects.


回答2:

If you are still into casting delegates you can find some more info about that here.