Home > other >  Can I get an Object from a collection if there's a single Item, but a List<Object> if the
Can I get an Object from a collection if there's a single Item, but a List<Object> if the

Time:01-26

I'm not sure if this can be done...

I'm trying to create a Dice class and a DiceSet class in Unity. A DiceSet has a List<Dice>, but I want a DiceSet with one dice to be implicitly equivalent to a Dice. Is there a method or function that returns the item if it's the only item in the list, but still returns the list otherwise? (Perhaps using Linq, or something)

Currently, there's no inheritance between Dice and DiceSet, but I'm thinking if I make Dice inherit from DiceSet and just limit the number of dice in the set to 1, that would do. But, I'm also wondering if there's a better way to do it. I'm concerned that a single Dice would count as a DiceSet in situations where it shouldn't. Maybe I'm overthinking it.

It would also be nice if, when two Dice were added together, they'd make a DiceSet. Hmmm... Maybe DiceSet should contain a List<DiceSet> instead?

Edit: Some further information...

I'm trying to make Dice parsable from a string (ex. "3d6 1" would create a DiceSet of three Dice with six sides, and with a modifier of 1.

What I'm thinking from your comments, I should forget the "DiceSet" concept and just make Dice contain a List<Dice> itself, and if it only contains one dice, it's still just a Dice.

Below is an example of what I'm thinking now. Is this thinking correct?


public class Dice : IDice, IRollable, IModifiable
{
    // Set containing quantities for each kind of dice
    public Dictionary<Dice, int> Set { get; set; }

    // implement IDice
    public int NumSides => SideValues.Count;
    public List<int> SideValues { get; private set; }

    // implement IModifiable
    public int Modifier { get; set; }
    public int ModifiedValue => RolledValue   Modifier;

    // implement IRollable
    public int RolledValue { get; protected set; }
    public void Roll() {
        RolledValue = SideValues[Random.Range(0, NumSides   1)];
    }

    // Dice constructor
    public Dice(int sides = 6, int quantity = 1, int modifier = 0) {
        SideValues = new List<int>(Math.Max(sides, 1));
        for(int i = 1; i < NumSides   1; i  ) {
            SideValues.Add(i);
        }
        Modifier = modifier;
        AddDice(this, quantity);
    }

    // Adds dice to the set
    public void AddDice(Dice dice, int quantity){
        if(Set.ContainsKey(dice))
            Set[dice]  = quantity;
        else
            Set.Add(dice, quantity);
    }

    // String conversions
    public override string ToString() {
        // ToDo
    }
    public void FromString(string diceString){
        // ToDo
    }
}

CodePudding user response:

Depending of the functionaliy DiceSet should provide, you could use the Composite pattern C# to make clients working with the DiceSet class unaware of how many Dice are in the DiceSet.

CodePudding user response:

In C#, a method can return only one type. It is also not possible to declare two methods with the same name, same parameters and different return types.

Depending on the scenario, it is sometimes necessary either to return different kinds of the same thing, which can be achieved by returning an interface and using different implementations of it, or to return a different number of elements of the same type (or interface).

The second case fits your problem. Here you should return a collection type. The caller can then check whether the collection has zero, one or many elements and act accordingly. The type of collection to return depends on several factors. Depending on your use case you should consider IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlyList<T>, IList<T>, ISet<T> or even a concrete class like List<T> or HashSet<T>.

Note that especially the interface IEnumerable<T> can be evaluated lazily. This can lead to some performance improvements if used wisely, or to worse performance, unintended behaviour or strange effects if used incorrectly.

So, in your specific case, you already seem to have a wrapper for a collection of an arbitrary number of Dice called DiceSet. This set should have a collection of Dice and operate on it. In this case it doesn't matter if the set contains one or more dices, the user of the set always executes the methods of the set class or probably iterates over all containing dices and calls a method on them and aggregates the result, where it also doesn't matter if the collection contains one or multiple elements.

  • Related