简体   繁体   中英

Kotlin generic collections as function parameter

In my Android app, I have a parent class named FilterOption which has 2 child classes named UserFilterOption and BusinessFilterOption .

abstract class FilterOption<T> {
    abstract fun match(filter: T): Boolean
}

The child classes implement this class and pass their T types, as expected. This is fine.

I have another function in my custom View class that takes a Set<> of these filters and does work on them:

interface FilterableView<T> {

    fun onFilterOptionChanged(filterOption: FilterOption<T>)

    private fun addFilter(menu: Menu, labelResId: Int, filterOptions: Set<FilterOption<T>>, filterOption: FilterOption<T>) {
        menu.add(labelResId).apply {
            isCheckable = true
            isChecked = filterOptions.contains(filterOption)

            setOnMenuItemClickListener {
                onFilterOptionChanged(filterOption)
                true
            }
        }
    }
}

I define my Views like this:

class BusinessFragment : FilterableView<BusinessFilterType> {
   ....
}

But when I try to call this function in the FilterableView class, I get errors:

private fun addBusinessFilters(menu: Menu, businessFilterOptions: Set<FilterOption<T>>) {
    addFilter(
        menu, R.string.general_open, businessFilterOptions,
        BusinessFilterOption.BusinessType.Open  <-- ERROR HERE
    )
    addFilter(
        menu, R.string.general_closed, businessFilterOptions,
        BusinessFilterOption.BusinessType.Closed  <-- ERROR HERE
    )
}

ERROR:

Type mismatch.
Required: FilterOption<T>
Found: BusinessFilterOption.BusinessType.Open

This is the same for the other type ("Closed"), as well as all the other types on the UserFilter .

This is the definition of the BusinessFilters:

sealed class BusinessFilterOption : FilterOption<Business.View.BusinessModel>() {

    sealed class BusinessFiltersType(private val type: BusinessFilterType) : BusinessFilterOption() {
        override fun match(filter: Business.View.BusinessModel): Boolean {
            //check if match with open or closed
        }

        object Open : BusinessFiltersType(BusinessFilterType.OPEN)
        object Closed : BusinessFiltersType(BusinessFilterType.CLOSED)
    }
}

So what i'm trying to do is make the addfilter method generic so I can pass UserFilterOption and BusinessFilterOption to it, because they both inherit from FilterOption<T> , so I don't understand why the error is telling me I need to pass the parent class, when I'm passing the child class.

Can anybody help? Thanks

T of addFilter is defined in FilterableView<T> . This means that the type passed to FilterableView determines the valid parameters that can be passed to addFilter . For BusinessFragment , only BusinessFilterOption would be allowed.

Where is addBusinessFilters defined? This method seems counterintuitive given the generic FilterableView<T> you have defined prior.

So what i'm trying to do is make the addfilter method generic so I can pass UserFilterOption and BusinessFilterOption to it

Do not confuse generics with inheritance , although you might be interested in reading more about generic constraints .

If that is what you want, you need polymorphism, and your view should be allowed to take any FilterOptions<T> . At the risk of not understanding your design considerations, you likely want to not make FilterableView<T> generic and instead make addFilter a generic method.

private fun <T> addFilter(
    ...,
   filterOptions: Set<FilterOption<T>>,
   filterOption: FilterOption<T>
) { ... }

I think the only issue you have is with the declaration of your BusinessFragment . Your FilterableView interface takes in a T which is the same type as the T in your FilterOption .

Your BusinessFilterType classes are FilterOption<Business.View.BusinessModel> , so your BusinessFragment should be declared as BusinessFragment<Business.View.BusinessModel> rather than BusinessFragment<BusinessFilterType> .

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