Jump to content
  • Advertisement
WolfWin

Best practice for passing data in C#?

Recommended Posts

What are some good practices for passing around data in C#? What are the pros and cons of using custom container classes versus a list or a dictionary or array?

Share this post


Link to post
Share on other sites
Advertisement

Lists are excellent for storing variable amounts of data of a specific type.

Dictionaries are excellent for storing variable amounts of data of a specific type when you need to index it by another type.

Arrays are excellent for storing a specific amount of data of a specific type.

Custom classes are excellent for storing variable or specific amounts of data of multiple types.

 

A good rule of thumb is this: don't reinvent the wheel. The List, Dictionary, and Array classes are highly optimized and the odds are they will work for most applications. That said, sometimes custom classes are just more convenient so don't be afraid to make them when you need them.

Also, I should point out that when "passing around" reference objects via function calls and the like you aren't actually passing the entire object, just a pointer to the object in memory. If you meant cross-class communication instead, that is a different beast, but I don't want to misinterpret what you said so feel free to ask for more details if that's the case.

Share this post


Link to post
Share on other sites

Basically what cjmarsh said.  Use the standard System.Collections.Generic collections (List, Stack, Queue, Dictionary, HashSet) for most things and only make a custom collection if it has some special behavior you need.  You probably won't need any other collections for a long time.  The main container class I can think of that I've written myself is a priority queue for A*.

However, since I remember posting a reply in your thread about RPG stats (comparing dictionaries to classes-with-fields), I want to make sure we're on the same page:  When we say 'custom container class' we mean a type that's specifically meant to contain data (usually all of the same type), without the container caring about the semantics of any element (i.e. the Dictionary doesn't know that it's containing RPG stats; it just sees keys and values and doesn't care what they mean).  Usually every element in a container is treated the same way by the container's code.  In your thread about RPG stats, the suggestion I made about having each stat as a field in a class would NOT be considered a 'container' class.  Each field in a class like that has a specific meaning and is treated differently by the program.

Usually you can identify when something is a container class or not by if it has some of these typical functions: Add, Remove, Insert, Push, Pop, Peek, Enqueue, Dequeue, or a square-bracket indexer.  If it just has a bunch of fields that you can directly get or set then we don't typically call those containers.

Edited by Nypyren

Share this post


Link to post
Share on other sites

Yeah I redid a bit of a class that holds Stats for a character and incorporated some of your advice. Though quick and dirty. It already feels better.
I added a bit of functionality but some of it is probably unnecessary. Handles lvl, exp, modifiers from status ailments or equipment etc.

So from what you are saying it would probably be best to pass stats or other data in dicts lists or arrays? Ex: StatSheet.Get can send a dictionary<statID, value>


	public class StatSheet
{
    public int
        Level = 0,
        EXP = 0,
        
        HP = 0,
        HPMax = 0,
	        SP = 0,
        SPMax = 0,
	        Strength = 0,
        Speed = 0,
        Soul = 0;
	    private Dictionary <MID, Modifier> mModifiers = new Dictionary <MID, Modifier>();
	    public StatSheet()
    {
        mModifiers = new Dictionary<MID, Modifier>();
    }
	    public StatSheet(Dictionary<SID, int> newStats)
    {
        Set(newStats);
        mModifiers = new Dictionary<MID, Modifier>();
    }
	    public void Set(Dictionary<SID, int> newStats)
    {
        foreach (KeyValuePair<SID, int> stat in newStats)
        {
            this.Set(stat.Key, stat.Value);
        }
    }
	    public void Set(SID statID, int value)
    {
        switch (statID)
        {
            case SID.Level:
                Level = value;
                break;
            case SID.EXP:
                EXP = value;
                break;
	
            case SID.HP:
                HP = value;
                break;
            case SID.HP_Max:
                HPMax = value;
                break;
            case SID.SP:
                SP = value;
                break;
            case SID.SP_Max:
                SPMax = value;
                break;
	
            case SID.Strength:
                Strength = value;
                break;
            case SID.Speed:
                Speed = value;
                break;
            case SID.Soul:
                Soul = value;
                break;
            default:
                Debug.LogError("Nonexistent Stat Type Added");
                break;
	        }
    }
	    public int Get(SID statID)
    {
        switch (statID)
        {
            case SID.Level:
                return Level;
            case SID.EXP:
                return EXP;
	
            case SID.HP:
                return HP;
            case SID.HP_Max:
                return HPMax;
            case SID.SP:
                return SP;
            case SID.SP_Max:
                return SPMax;
	
            case SID.Strength:
                return Strength;
            case SID.Speed:
                return Speed;
            case SID.Soul:
                return Soul;
            default:
                Debug.LogError("StatSheet: Cannot find stat type:" + statID.ToString());
                return 0;
	        }
    }
	    public Dictionary<SID,int> Get()
    {
        Dictionary<SID, int> rawStats = new Dictionary<SID, int>();
        rawStats.Add(SID.Level, Level);
        rawStats.Add(SID.EXP, EXP);
	        rawStats.Add(SID.HP_Max, HPMax);
        rawStats.Add(SID.SP_Max, SPMax);
	        rawStats.Add(SID.Strength, Strength);
        rawStats.Add(SID.Speed, Speed);
        rawStats.Add(SID.Soul, Soul);
	        return rawStats;
	
    }
	    public void Add(SID statID, int value)
    {
        int newValue = this.Get(statID) + value;
        this.Set(statID, newValue);
    }
	    public void Add(Dictionary<SID, int> stats)
    {
        foreach (KeyValuePair<SID, int> stat in stats)
        {
            this.Add(stat.Key, stat.Value);
        }
    }
	    public Dictionary<MID, Modifier> Modifiers
    {
        get{return mModifiers;}
        set{value = mModifiers;}
    }
	    
	    public void AddModifier(MID modID, Modifier modifier)
    {
        mModifiers.Add(modID, modifier);
    }
   
    public void RemoveModifier(MID modID)
    {
        mModifiers.Remove(modID);
    }
}

Share this post


Link to post
Share on other sites

You're on the right track but I'd recommend taking another step back and looking at what that class actually does. You have a list of integers and a series of functions that gets and sets the value of them based on another index. Ignoring for a moment the Dictionary of modifiers, doesn't that behavior sound just like what a Dictionary itself does? In fact, a Dictionary is just a class with methods similar to your own but the get and set operations are abstracted away in brackets and the assignment operator. Consider instead just using two Dictionaries, one for the stats and one for the modifiers.

Share this post


Link to post
Share on other sites

  • Advertisement
  • Advertisement
  • Popular Tags

  • Popular Now

  • Advertisement
  • Similar Content

    • By Armaan Gupta
      Hey There,
      I am a developer and Im working on a blockchain based infinite runner type game. Right now, I am working on releasing the beta version with a couple other game developers, but would love to expand the team and have other talented and bright people contributing. The game portion of the project isnt very complicated, and wouldnt require anyone to pull thier hair out for it.
      If you are interested in joining a project, interested in the idea, or would like some more information, please don't hesitate to ask either by commenting, discord (username: Guppy#7625), or by email (armaangupta01@gmail.com).
      Thank you!
    • By bojanzarnoski@gmx.de
      Hello,
      I want to get into coding again by programming a 2D platformer to get started, but i don't know if i should use Java or C# with the unity engine.
      I am pretty fit with Java, but with c# i have to start from scratch. What do you recommend and why?
    • By SickTwistGames
      Ok, firstly, Hi.
       
      This is my first post on this forum. I am an Indie Dev making my first game so bear with me when I say dumb stuff, I'm on a huge learning curve.
       
      My first question is about inventory systems for unity. I am trying to make a survival type game with crafting. I have purchased Inventory manager pro by devdog from the unity asset store and it seems like a pretty powerful assett but for an intermediate coder its a little tough to use.  I'm beginning to wonder if it was the right purchase.
      So my question is.... does anyone have any experience of inventory plugins / systems for unity and can anyone reccomend a system to me?
      It needs to have the following: Loot system, crafting system, character sheet, blueprint system,  character stats system. Ideally with as little coding as possible.
       
      Thanks
    • By ethancodes
      I've got a bug with my brick breaker style game. The bricks move down one line at a time ever 1.5 seconds. What appears to be happening is occasionally the ball will be just about to hit the brick when the brick moves down a line, and now the ball is behind it. I'm not sure how to fix this. I have two ideas but I'm not sure of implementation. 1 solution would be to check where they were and where they are going to be before rendering the frame. Then if they crossed paths, then register the brick as hit. Solution 2 would be change how the bricks move. I could maybe slide them down line by line, instead of a jump down. I'm not sure of this will fix the issue or not. Any ideas?
    • By Scouting Ninja
      Once again Unity is frustrating me to the point of insanity.
      What I am looking for is a way to find a ray intersect with the edges of the mesh, using Unity's already made collision system. I want to point out that I know how to do a line intersect, what I want to know is if Unity supports this already.

      The image above shows how I sweep a ray,intersecting the mesh. The top green image shows what I want and the red shows what Unity is giving me.
      I want to know if there is some way, to find the edges in Unity without creating a custom line intersection tool.
      Most engines I know don't use rays for this but instead use a plane like this:

      I checked the Unity "Plane intersection" but it is just a ray cast. It will still need me to find the vertices on the collision mesh to cast the ray from; if I am doing that then making my own line intersection tool is better.
       
      I looked online and can find anything on this. Also I don't want to cut the mesh, so I don't need a way to know what side is what.
      Does Unity even have collisions that support edge only detection?
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!