Skip to main content
GameDev.net gamedev.net
🔒 Locked 🎮 Unity

Reference/Value types in C#

Started by Fl00Fy Nov 10, 2013 at 2:29 PM 4 replies 2.8k views
Original Post
Fl00Fy
Fl00Fy

I'm busy trying to make a game in Unity3D, but haven't had much experience in C# and having some trouble finding any specifics on how value/reference types are handled. I understand the basics of it; that most primitive data types, structs and enums are value type (unless specified by the ref qualifier), and all classes are reference types. Knowing that, I'm assuming the code I've currently got isn't working the way I meant it to because of my lack of knowledge. I'm trying to make a fairly simple card game, and have a Hand class, and a Deck class, both of which are simply containers for Card objects.


public class Deck
{
	private List<GameObject> cards;
	private const int TOTAL_CARDS = 52;
	private int iterator;

        //Constructors...

	public GameObject drawCard()
	{
		if (cards.Count == 0)
		{
			//Merge discard pile with deck
		}
		GameObject temp = cards[iterator];
		cards.RemoveAt(iterator++);
		
		return temp;
	}
}

public class Hand{
	
	private List<GameObject> cards;
	private int numCards;
	private Deck deck;
	
	public Hand(Deck deck)
	{
		this.deck = deck;
		numCards = 0;
		cards = new List<GameObject>(15);
	}

	public void drawCard()
	{
		GameObject card = deck.drawCard();
		Transform cardTransform = card.transform;
		cardTransform.position.Set(1, 1, 1);
		cardTransform.Rotate(new Vector3(0, 1, 0), 180);
		cards.Add(card);
		numCards++;
	}
}

Above is a simplified version of those two classes, the methods the question pertains to is the drawCard() methods in both classes. In the Deck's drawCard method, would removing the object from the List remove a reference or an object; and would the object returned by that method and used in the Hand's drawCard method be a reference pointing to an object that has been deleted(removed from the list) or will it be retained?

Thanks for any help.

Zaoshi Kaba
Zaoshi Kaba

Judging by your previous posts you seem to have experience with C++. You can think of objects as pointers to objects. When you remove one from List<> you simply remove pointer, but do not delete object itself (memory leak), but in C# garbage collector prevents those leaks. Therefore removing from a List<> will remove only reference.

Samith
Samith
In C#, as long as you still have a reference to an object it won't be deleted. So if your object is in the Hand list as well as the Deck list and you remove it from one list, the reference that the other list holds will prevent the object from being deleted.
Fl00Fy
Fl00Fy

Alright thanks. That simplifies it a lot for me.

Starnick
Starnick

When in doubt, the MSDN C# docs usually are a good resource.

A value type is like a "lightweight class", it's allocated on the stack. A reference type is an object that is allocated on the heap. So, you can declare a value type/reference type both with the new keyword, but only the reference is allocated on the heap, which will get cleaned up by the GC when no one references it anymore. You can still have memory leaks in the managed world, although it's a lot harder to do. Basically, if you have something that has resources to it, but always hold a reference to that object, then it won't be GC'ed, then presto you have a resource you may have intended to be cleaned up, still alive somewhere. You may want to read up on the "Dispose pattern".

Note that a reference is exactly that, your variable of type Deck/Hand isn't the object, it refers to an object on the heap. And it's not like a pointer either, because the runtime manages your memory, which means objects can be moved around on the heap. In your case, the list is holding a reference to an object on the heap. If you look up that object in the list, it's still a reference to the same object. If you remove that object, and it's not referenced anywhere else, then at some time in the future the object will be GC'ed. The same is not true for value types. Example: Add a value type to a list, then modify the value - the one in the list will not reflect the change, because it was copied.

Read up on the ref/out keywords, as judging by your post there's some confusion on those. By default, everything is pass by value. For reference types, this doesn't matter because the object exists on the heap (the reference is still copied, but the object itself isnt). But this has a big impact for value types. When you pass a struct to a function, the whole object gets copied. So if you modify a field on that parameter lets say, then you return back, the struct you passed in won't appear to be modified. That's where the ref/out keywords come into play, because if you pass a struct by reference, then it's not copied. This also can have performance implications for large structs (e.g. a 4x4 matrix of floats - 64 bytes).

Regarding Enums. They're a slightly different beast. They inherit from the base class "Enum" (that's a capital E) and enums are represented by an underlying type such as byte, int, etc (pretty much all the primitive types).

Eck
Eck

It looks like your question is pretty well answered Fl00Fy, but you might want to give a post I wrote about equality of reference types and value types a quick read.

http://www.gamedev.net/topic/649248-list-remove/?view=findpost&p=5103729

It might save you some headache if you have to remove a specific card.

- Eck

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.