Search code examples
c#.netoopgenerics

How to make a generic Delete function for different business objects in C#


I have several classes (bizMember, bizParsha, and bizEarningYear), all of which inherit from a generic base class bizObject<T>. Each of these classes has a Delete(int id) method that removes an item from the database.

Currently, I have a DeleteItem method that checks the type of the passed-in object using is, then calls the appropriate Delete method. However, this approach is not scalable. I want a more generic way to handle this so that I can pass in any class that inherits from bizObject<T> and have it automatically call its Delete method.

Here’s my current implementation:

private async Task DeleteItem(object item)
{
    if (item is bizEarningYear bey)
    {
        await bey.Delete(bey.EarningYearId);
        await _viewmodelbinder.LoadEarningYearList();
    }
    else if (item is bizParsha bp)
    {
        await bp.Delete(bp.ParshaId);
        await _viewmodelbinder.LoadParshaList();
    } 
    else if (item is bizMember m)
    {
        await m.Delete(m.MemberId);
        await _viewmodelbinder.LoadMemberList();
    }
}

private async void Delete_Clicked(object sender, EventArgs e)
{
    if (sender is Button b && await PromptBeforeDelete(b.Parent.BindingContext))
    {
        try
        {
            await DeleteItem(b.Parent.BindingContext);
        }
        catch (Exception ex)
        {
            await DisplayAlert(this.ToString(), ex.Message, "Close");
        }
    }
}

What I Need:

  • A scalable way to remove the type-checking (is statements).
  • A generic function that works with any bizObject and calls its Delete method dynamically.

Constraints:

  • The classes (bizMember, bizParsha, bizEarningYear) all inherit from bizObject<T>.
  • Each class has a Delete(int id) method that takes the object's ID as a parameter.
  • I need to update a corresponding list in _viewmodelbinder after deletion.

How can I refactor DeleteItem to be more generic and scalable?

I attempted to use generics like this:

private async Task DeleteItem<T>(bizObject<T> item) where T : bizObject<T>, new() 
{
    //code here
}

However, I ran into an issue when trying to pass the BindingContext from the button click event. At the time of the event, I don’t know the type of the clicked object, so I can’t cast it to the correct generic type.


Solution

    1. To implement deletion, define an abstract Delete() method in the base class bizObject<T> and concrete implementations of the corresponding method in the child classes (bizMember, bizParsha, bizEarningYear). In this case, you can use polymorphism: calling a method on a reference of a base class, you can receive a call to a method of a specific implementation of that class. This way you will get rid of the need to have ifs and type checking.
    2. An elegant solution to updating the viewmodel list can be to use the decorator pattern: define an interface instead of a base class and create an implementation that encapsulates some object corresponding to the interface, but overrides the Delete() method as calling Delete() on the encapsulated object and updating the viewmodel list. Then you wrap your child objects in a decorator object and thus add the functionality of updating the list to them.