It can only be either a single instance of T or an array of T[] but I don't know at compile time
You don't need to have both cases in your class then. Instead abstract their behaviour to the interface and have two implementations of that interface. One for single object and one for an array.
public interface IDataOf<T> { void Match(Action<T> match); void Match(Action<T[]> match); } public class SingleOf<T> { private readonly T _data; public SingleOf(T data) => _data = data; void Match(Action<T> match) { match(_data); } void Match(Action<T[]> match) { // do nothing or throw an exception } } public class MultipleOf<T> { private readonly T[] _data; public MultipleOf(T[] data) => _data = data; void Match(Action<T> match) { // do nothing or throw an exception } void Match(Action<T[]> match) { match(_data); } }
Example of usage:
Action<string> singleMatch = item => { }; Action<string[]> multipleMatch = items => { }; var text = new[] { "one", "two", "three" }; IDataOf<string> lines = new MultipleOf<string>(text); lines.Match(multipleMatch); var anotherText = "only one"; IDataOf<string> sentence = new SingleOf<string>(anotherText); sentence.Match(singleMatch);
Names of the classes should be based on their behavior.
Names of the variables should be based on their usage, easy to read and understand in the current context.
If you still want to have class with both options, name SingularOrArray is good enough and is not too long.
Eitherhas some other behaviour depending on the amount of elements, then that behaviour might give you a good name. However, I'm rather thinking this might be an X Y Problem. After all, an array with only one element is still a valid array and I can't think of anythingEither<>could do that an array couldn't withif(stringArray.Length == 1).