How to avoid circular dependency with composite pattern

  Kiến thức lập trình

I’m trying to build custom filtering using expression trees and I came across circular dependency issue.

I have the following interfaces implemented:

public interface IFilterExpressionProvider
{
    Expression GetExpression(FilterCriterionRequestDto filterCriterion, ParameterExpression parameter, Type ItemType);
}

and

public interface IFilterOperatorExpressionProvider
{
    bool Supports(FilterOperators filterOperator, Type propertyType);
    
    Expression GetExpression(PropertyInfo propertyInfo, ParameterExpression parameter, object? value);
}

then I have the composite root class which is iterating over operator expression providers:

public class FilterExpressionProvider : IFilterExpressionProvider
{
    private IEnumerable<IFilterOperatorExpressionProvider> _filterOperatorExpressionProviders;
    
    public FilterExpressionProvider(IEnumerable<IFilterOperatorExpressionProvider> filterOperatorExpressionProviders)
    {
        _filterOperatorExpressionProviders = filterOperatorExpressionProviders;
    }
    
    Expression IFilterExpressionProvider.GetExpression(args)
    { 
        foreach (var provider in filterOperatorExpressionProviders)
        {
            if(provider.Supports(filterOperator))
            {
                return provider.GetExpression(args);
            }
        }
    
        throw new ArgumentException("Could not find the proper operator expression provider");
    }
}

Everything is great so far, I have different operator classes such as Equals, GreaterThanOrEquals, LessThanOrEquals, Between, OneOf etc.

The use case is that I want to be able to reuse some of the operators inside of some other operators. For example I want to use the GreaterThanOrEquals and LessThanOrEquals in the Between operator or I want to use the Equals operator in the OneOf operator and I want to use the composite pattern as I could have different variations of each operator (due to handling different data types).

Problem:
Lets take the OneOf operator example from above.

If I inject IEnumerable<IFilterOperatorExpressionProvider> into its constructor obviously I will get circular dependency exception.

Workaround:
The only workaround I found is to create a separate interface such as IEqualsOperatorExpressionProvider and inherit both IEqualsOperatorExpressionProvider and IFilterOperatorExpressionProvider in the actual implementation and also register both variations of it in the .NET IOC container. This way in the OneOf operator class I’m able to inject it as IEnumerable<IEqualsOperatorExpressionProvider> but I feel this hacky and not sure if it is okay. Both interfaces are absolutely the same obviously.

Can you recommend me a way to achieve what I’m trying to do and also tell me if my workaround is fine ?

New contributor

user26338095 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Theme wordpress giá rẻ Theme wordpress giá rẻ Thiết kế website

LEAVE A COMMENT