Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I write a generic method signature that I could override in the inherited children?

I'm in a situation where I have a Bag that has a AddSlot method inside. I have two types of bags, ItemsBag and DCBag (stands for draggable content) ItemsBag is a 2D bag meaning it has rows and columns, DCBag is 1D, it has only one column but many rows (Which means I can consider it 2D as well).

Now the thing is, since the first bag deals with 2D indices, I would want AddSlot signature to be something like this:

public void AddSlot(int r, int c);

And the other bag's AddSlot:

public void AddSlot(int r);

How can I write a virtual/abstract signature of AddSlot in Bag such that when ItemsBag and DCBag inherit from Bag they can override the signature in the way I mentioned above?

As I said, I can consider the DCBag to be 2D as well, so that both it and ItemsBag have the same signature, but I really want to know if I could do this, it's very interesting.

I could get away using a variable number of arguments params obejct[] args but it would be nice to do it in a way that doesn't involve boxing/unboxing.

I could also make a TwoDimBag and OneDimBag make them both inherit from Bag, write the definitions of AddSlot in them the way I want to, and then make ItemsBag inherit TwoDimBag and DCBag inherit OneDimBag, but I'm not looking for work-arounds more than how to achieve what I'm asking for.

Again to recap one last time: how can I write a signature that I could override in the inheriting children? (that is, if I can and there is a way)

Thanks.

EDIT: (Extra Info) The Bag has a lot of functionality in it. The difference between the two bags is that ItemsBag holds a 2d List of Slot (List<List<Slot>>), while DCBag has a 1d List of Slot. It's the Slot that holds an Item. - Items in ItemsBag could take more than one Slot, items in DCBag take only one.

Some of the things you can do in both bags: AddSlot, FreeSlot, AddItem (adding strategy differs, there are also extra adding methods in ItemsBag), in both the bags you could pickup an item with your mouse, swap items, sort items, both bags also receive notifications from slots to take necessary actions like Notify_ClickedOnEmptySlot(Slot slot)

Some of things you can only do in ItemsBag: Combine items, adding a row of slots, adding a col of slots and rotate items.

Here's how the bags differ in terms of appearance, ItemsBag (here's an old demo):

enter image description here

DCBag:

enter image description here

like image 621
vexe Avatar asked Dec 19 '25 21:12

vexe


1 Answers

If the object is a bag of items, then consider making the item type generic.

I.e. you would have a generic Bag<T> class:

class Bag<T>
{
     private readonly List<T> _items = new List<T>();
     public void AddSlot(T item)
     {
         _items.Add(item);
     }
}

In that case, your item type can be anything:

class Item1D
{ 
    public int Value { get; set; }
}

class Item2D
{
    public int X { get; set; }
    public int Y { get; set; }
}

And providing that the "bag" functionality is the same for all items, you will instantiate different bags by passing the appropriate generic type:

var bag1D = new Bag<Item1D>();
var bag2D = new Bag<Item2D>();

Or, you could even pass a list of items as the generic parameter:

var bagOfSlots = new Bag<Slot>();
var bagOfListOfSlots = new Bag<List<Slot>>();

Check out the classes in the System.Collections.Generic namespace, that's the general idea. Also, whether you actually need to make it virtual depends on what the responsibility of the Bag class should be (check out the Single responsibility principle). A rule of thumb in OOP is to keep classes' responsibilities as simple as possible (and a "bag" implies simply an unordered collection of items).

[update]

If the DCBag is more or less an ItemBag with a single column, then you can use the new keyword to change the signature of the method while still having access to the base method:

class ItemBag
{
    public virtual void AddSlot(int r, int c)
    {

    }
}

class DCBag : ItemBag
{
    public new void AddSlot(int r)
    {
        // we only have a single column
        base.AddSlot(r, 0);
    }
}

Note that this is not overriding the method, but instead creating a new method with the same name. In other words, you can call:

ItemBag itemBag = new ItemBag();
itemBag.AddSlot(3, 4);

DCBag dcBag = new DCBag();
dcBag.AddSlot(3);

But you cannot have dynamic dispatch (I presume you don't need it anyway in this case):

// if dcBag is of type ItemBag
ItemBag dcBag;

// ...and you instantiate it to a DCBag...
dcBag = new DCBag();

// ...you still end up with a virtual signature...
dcBag.AddSlot(3, 4);

// ...and the new method is inaccessible
dcBag.AddSlot(3); // <-- this will not compile
like image 156
Groo Avatar answered Dec 21 '25 10:12

Groo