I'm writing some code which works on a collection and adds more information to it. It starts with A, and then adds some more information, say it calculates the "expiry" of A and returns that. Then I calculate the allowed permissions based on the current user, and A and B, - and add this, call it C.
I started off using Tuples, but by the time I got to (E) the type definitions were unwieldy, and difficult to understand.
Using Tuples:
IEnumerable<A> CreateA(); IEnumerable<Tuple<A,B>> AddB(IEnumerable<A>); IEnumerable<Tuple<A,B,C>> AddC(IEnumerable<A,B>); etc..
I'm considering two options, creating types which represent the Tuples (option 2 below) which means you can't create C without having done A and B at compile time, or use a mutable object with a runtime check (option 3 below)
Replace Tubles with distinct types
class AB { ctor(A, B), A A{get;}, B B{get;} } class ABC { ctor(A, B, C), A A{get;}, B B{get;}, C C{get;} } IEnumerable<A> CreateA(); IEnumerable<AB> AddB(IEnumerable <A>) IEnumerable<ABC> AddC(IEnumerable <AB>) etc..Have a mutable type (with some runtime checks, eg B is null then throw...).
class ABC { ctor(A), A A{get;}, B B{get;set;}, C C{get;set;} } IEnumerable<ABC> CreateA(); IEnumerable<ABC> AddB(IEnumerable<ABC>); //Sets B IEnumerable<ABC> AddC(IEnumerable<ABC>); //If B is null throw, set C
Option 2 it looks a little alien, and creating and naming the types gets almost as unwieldy as option A. I'm getting the feeling I've wandered a bit off the beaten track.
I think more programmers would understand option 3.
Is there a standard accepted pattern for option 2 with a standardised naming strategy - or should I just give up on this and settle on option 3.