How to inject repository in a C# IComparer class?

359 views Asked by At

I need to sort questions by its sort order.

One table named Questions stores the sort order info in QuestionId and SortOrder.

The other table ApplicantQuestions contains all the questions and answers, referencing the first table by QuestionId.

So basically we want to sort a list based on another list.

public class QuestionOrderComparer : IComparer<int>
{
    private readonly IRepository<Question> _Questions;

    public QuestionOrderComparer(IRepository<Question> Questions)
    {
        _Questions = Questions;
    }

    public int Compare(int x, int y)
    {
        var questionsInOrder = _Questions.All
            .Select(q => new QuestionOrderModel(q.QuestionId, q.SortOrder))
            .ToList();

        var xValue = questionsInOrder.FirstOrDefault(q => q.Id == x)?.SortOrder ?? 0;
        var yValue = questionsInOrder.FirstOrDefault(q => q.Id == y)?.SortOrder ?? 0;
        return xValue - yValue;
    }
}

That looks fine, but when I try to use it

thisSetOfApplicantQuestions
    .OrderBy(x => x.QuestionId, new QuestionOrderComparer());

the intellisense requires me to add some parameter for IRepository<Question>.

How to deal with that? Is it possible to have injection inside an IComparer class?

2

There are 2 answers

0
MistyK On BEST ANSWER

What about hiding repository behind factory? Structure map will resolve everything for you.

public class QuestionOrderComparerFactory : IQuestionOrderComparerFactory
    {
        private IRepository<Question> _questions;

        public QuestionOrderComparerFactory(IRepository<Question> questions)
        {
            _questions = questions;
        }

        public QuestionOrderComparer Create()
        {
            return new QuestionOrderComparer(_questions);
        }

    }



    thisSetOfApplicantQuestions.OrderBy(x => x.QuestionId, _comparerFactory.Create()); // comparer factory is injected via constructor

Btw I wouldn't put this logic in a comparer unless you want to reuse it in many places. I always thought of using comparer in very simple cases without any external dependencies.

0
radarbob On

Dump the comparer and put that code in a Sort method in a questions collection object.

This code is conflating comparing and sorting. Traditionally a class overrides CompareTo, or has a customer comparer. The .net framework knows to use this when calling sort on a collection of questions. A "compare" method should be comparing - returning -1,0,1 (less than, equal, greater than, respectively) - not doing the actual sorting. I can see LINQ changing that paradigm, but still, Compare doing sorting seems to be working against the framework. Then, the Questions collection should have-a comparer, not vice versa.