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.