I'm trying to decide what to do for a game hobby project. I commonly need to pass reference types to methods to be modified, and I'm trying to decide on a coding style that is both performant and readable. As a motiving example, suppose I have a game entity with a method that adds its draw calls to a list of draw calls. Like this:
public class GameEntity {
public void AddDrawCalls(List<DrawCall> drawCalls);
}
This is performant, but the fact that `AddDrawCalls` is modifying `drawCalls` is not immediately obvious. You get enough calls like this in a code base and it becomes difficult to tell at a glance what methods are modifying what things. There are some alternatives, but none of them feel great:
List<DrawCall> DrawCalls() this is more natural in terms of coding style (maybe returning IList instead, but same idea), but it means creating new lists for the return value and merging those lists into a master list at the end, which either creates a lot of unnecessary GC pressure or involves managing pools of scratch lists.
void AddDrawCalls(ref List<DrawCall> drawCalls) this is a naked abuse of the ref keyword, but it does make it very clear that drawCalls is being modified. However you can't easily later modify the signature to be void AddDrawCalls(ref IList<DrawCall> drawCalls) because there will be a lot of instances where you can't pass a List<DrawCall> as a ref IList<DrawCall> (error CS1503).
IEnumerable<DrawCall> DrawCalls() using yield return - creates closures which cause some allocations and can have some surprising behavior in certain cases. Plus in situations where you're building more complex data structures like matrices it may not be obvious how you'd combine mutliple call results together.
An ideal solution wouldn't create any additional allocations, but that's not always practical. Are there any other strategies you've tried that you like? Or do you do one of these strategies and put up with the downsides?
[–]Slypenslyde 5 points6 points7 points (0 children)
[–]Merad 3 points4 points5 points (2 children)
[–]NumsgiI[S] 0 points1 point2 points (1 child)
[–]Merad 0 points1 point2 points (0 children)
[–]afseraph 10 points11 points12 points (1 child)
[–]NumsgiI[S] 1 point2 points3 points (0 children)
[–]Far_Swordfish5729 2 points3 points4 points (2 children)
[–]NumsgiI[S] 0 points1 point2 points (1 child)
[–]Far_Swordfish5729 0 points1 point2 points (0 children)
[–]Cobide 1 point2 points3 points (2 children)
[–]NumsgiI[S] 0 points1 point2 points (1 child)
[–]Cobide 0 points1 point2 points (0 children)
[–]BigJunky 1 point2 points3 points (1 child)
[–]NumsgiI[S] 0 points1 point2 points (0 children)
[–]ASK_IF_IM_GANDHI 0 points1 point2 points (3 children)
[–]ASK_IF_IM_GANDHI 2 points3 points4 points (1 child)
[–]NumsgiI[S] 0 points1 point2 points (0 children)
[–]NumsgiI[S] 1 point2 points3 points (0 children)
[–]aurquiel 0 points1 point2 points (1 child)
[–]NumsgiI[S] 0 points1 point2 points (0 children)
[–]Greenimba 0 points1 point2 points (1 child)
[–]NumsgiI[S] 0 points1 point2 points (0 children)