In this lecture, we'll look at the implementation of our ConfigurationData in our Feed the Teddies game. This is my ConfigurationData file. As you can see, I'm using a different format than the format we looked at before. In this format, each row has a ConfigurationData value name and the value for that name. In the past, the first row was all of our ConfigurationData value names and the second row was all of our ConfigurationData value values. That was much harder to read because you scrolled left and right. This is a much easier to read format in the CSV file and we'll also see that we gained another benefit from doing it this way when we look at our ConfigurationData class. There are 35 ConfigurationData values in this comma separated value file. I know this looks like a spreadsheet because I opened it in Excel, but it really is a CSV file. In our code, I've added an enumeration of the ConfigurationData value names. Here are those 35 data value names. The order in which they appear here in the enum doesn't matter at all, but these are the 35 ConfigurationData values that we have in our CSV file. Our ConfigurationData class is significantly different from what we've seen before. We still have a constant string that saves the name of the ConfigurationData file, but I'm going to store all of my ConfigurationData into a dictionary. The key for the dictionary is that enum that we just looked at and the value in the dictionary is a float. Now there are some ConfigurationData values that are more appropriately integers rather than floats and we'll handle that when we expose the properties for those particular values. Speaking of that, the very first property we have is TotalGameSeconds, which is an int. When I implemented the get accessor for this, the first thing I do is I access in my values dictionary the value that's keyed by TotalGameSeconds. That gives us the TotalGameSeconds, but that's a float. To return an int, I just type-cast it to an int. This is great because storing everything in a dictionary of floats simplifies our code here, but we can still expose integer or properties by just type-casting those values. This is information hiding again because the consumer of the class has no idea that we've stored this as a float. All they know is they access that information as an int. Our constructor is also significantly different. We still have a stream reader and we still open a text file, but the way we populate our values is we use a while loop because we have a bunch of rows and we don't want to hard code how many rows there are, so we can use a while loop. Once currentLine is in fact null, that means we've reached the end of the file, so we'll stop reading them. We do an input ReadLine and put it into currentLine. Then we split that line into tokens. We've seen this split method before. We used it previously to split value names or to split values, but here we're splitting our string, which is a valueName, the value into two tokens. The next thing we do is we need to parse the valueName into this enum type so that we can use it as a key in our dictionary. This looks complicated here. Basically, we take tokens 0, which is the value name, and we're going to use Enum.parse to parse it into a ConfigurationData value name, but we still have to type-cast it to that enum datatype and then finally we can put it into valueName. You can read the documentation for Enum.parse if you want to, but this is the way that we can parse a string into an enumeration value. That's the hard piece. The easy piece is to parse our second token, tokens 1 into the value which is a float, and add it to our dictionary of values keyed by the valueName we just figured out right here. Then we read the next line in the file. We keep doing this until we reach the end of the file and then we've put all of the values into the dictionary keyed by the value name. One of the great benefits of using this dictionary approach is we don't have to know what order the ConfigurationData values are in the CSV file. All we have to know is that we have the right names in our enum and then we can just go through and read them in and it doesn't matter what order they are in that file. That's a huge benefit as our ConfigurationData files get bigger. The other thing you might wonder is why are we keying by an enum if we have to do all this work, why didn't we just use string as the key and then we could have just used tokens 0 and not had to do all that work to parse that string into an enum value. The reason I'm using an enum is if I use a string, it's easy to miss type strings, get the spelling wrong or something like that and I use these keys a lot in my code. If I mistype a string, it will compile fine. It just won't work when I run it, but if I miss type an enum name, the compiler won't let me get away with that. It will require me to get the enum name right. This is a safer datatype to use for the key so that I can catch those issues at compile time rather than at runtime. Unfortunately, something could go wrong. For example, we may have tokens 0 that doesn't actually parse it into a ConfigurationData value name enum value and that would cause an exception to be thrown. Or one of the values that was provided is not parsable into a float and that could cause an exception to be thrown or something happens with the file. If an exception gets thrown, we want to set default values for everything in our dictionary. We'll take a look at that soon. Finally, when we're all done, whether an exception was thrown or not, we close our input file. For setting the default values, first, you can see I have a whole bunch of code here that adds default values to the dictionary for every single one of those ConfigurationData value names. I have to clear my dictionary first though before I do this. Because it could be the case up here that I actually end up throwing the exception after I've put 20 things into the dictionary and I'm trying to put the 21st value in and something goes wrong, and so I throw the exception. If I don't clear my dictionary down here, I already have 20 things in my dictionary and when I try to add one of the data values with a duplicate key, I'll get an exception thrown because I'm trying to add something to the dictionary that has the same key as something that's already in the dictionary. I clear the dictionary first and then I manually add default values for every single ConfigurationData value. Finally, our ConfigurationUtils class is the same approach that we've seen before in the ConfigurationUtils class. We don't care that ConfigurationData uses a dictionary rather than some other mechanism for storing the values, because that's information that's hidden in ConfigurationData. All we need to do is we have a field to hold a ConfigurationData object, and we expose all those properties, but each property is just wrapping the same property that's in ConfigurationData. Finally, we have our initialized method that simply initializes our ConfigurationData field to a new ConfigurationData object. That's how we can implement a more robust ConfigurationData approach using dictionaries in our Unity Games, and one of the huge strengths of this approach is we don't have to care what order the ConfigurationData appears in our CSV file. We can just process the file with no issues at all. A secondary benefit is the CSV file is easier to read and that's helpful for game designers as they're doing the tuning values, it's far easier and more natural for people to scroll up and down than to scroll horizontally. To recap, in this lecture we saw another good use of dictionaries, we saw a different format for our CSV ConfigurationData file, and we saw that we can end up with a lot of ConfigurationData values.