0

I'm going to use the example of ISO 3166-1 country definitions for this. In the standard, you may have 3 values: the alpha2 country code "CA", the alpha3 country code "CAN", and the numeric code "040". All of these map to the country Canada. I mustn't be able to use an external data source or load a text file at random.

I can store these in a dictionary as below:

enum Country { Canada, UnitedStates };

void Main()
{
    Dictionary<string, Country> countries = new Dictionary<string, Country>();
    countries["CA"] = countries["CAN"] = countries["040"] = Country.Canada;
}

The problem with this is that I would have to add a line for each country that I want to add. That's a lot of country codes to type in, and a lot of enum values to create.

It seems like what I want to do is have an "in-code database" that is compiled into the assembly. One option would be to add a resources file and parse the file every time, but that seems too slow and wasteful. Storing the parsed collection in binary format seems attractive.

How can I store these 3 values as well as a full country name for every recorded country inside of my program? Is there a logical and well-known design pattern for dealing with this data problem?

TylerH
  • 20,799
  • 66
  • 75
  • 101
  • `Dictionary countries = new ...` this is not C – David Ranieri Jan 23 '17 at 20:42
  • I was about to say :-) Did you mean to tag this C# @CanadaIT? – Jonathan Gilbert Jan 23 '17 at 20:42
  • 2
    Possible duplicate of [Multi-key dictionaries (of another kind) in C#?](http://stackoverflow.com/questions/1171913/multi-key-dictionaries-of-another-kind-in-c) – rene Jan 23 '17 at 22:09
  • @rene Thanks, but it's not. I'm asking about dealing with the data, not the .Net constructs. –  Jan 23 '17 at 22:19
  • Huh? So you have this list/csv/excel that contains all that countries stuff and the enum they belong to and you want to have code from that, right? If yes, maybe look into [t4 templating](http://stackoverflow.com/search?q=%5Bc%23%5D+t4+) – rene Jan 23 '17 at 22:23

3 Answers3

0

In C#, there is no way to "preinitialize" an object in the compiled image, as you can with C/C++. This is because the compiled image isn't actually made up of the physical bits that are executed, and because the object & type system that the .NET Framework uses makes objects more than just an arrangement of bits at a particular memory address -- all objects have vtables, are relocatable by the GC, and have type metadata. It's too much to statically represent in the file. As such, any object whose data was static in the file would have to be "rehydrated" at load time anyway, so there would be no advantage to storing the raw bits over simply writing code to instantiate the object.

As such, this is what you'll need to do. There are a few approaches. One is to come up with a concise text format for the data and embed a string with all the data into it in the program. Then, in a static constructor, once at app startup, you can parse that string into a Dictionary<,> for efficient access.

Another approach is to write a separate application whose purpose is to write initialization code for you -- a "code generator". The code generator, then, reads in the data in whatever format you have available, and then spits out a large block of C# code that would be unwieldy and error-prone to write by hand, e.g.:

static readonly Dictionary<string, Country> CountriesByISOCode;

static Countries()
{
  var countriesByISOCode = new Dictionary<string, Country>();

  countriesByISOCode["AF"] = "Afghanistan";
  countriesByISOCode["AFG"] = "Afghanistan";
  countriesByISOCode["AL"] = "Albania";
  countriesByISOCode["ALB"] = "Albania";
  countriesByISOCode["DZ"] = "Algeria";
  countriesByISOCode["DZA"] = "Algeria";
  .
  . // (about 475 more lines here, all written for you by the code generator)
  .

  Countries.CountriesByISOCode = countriesByISOCode;
}

You can then confidently copy/paste that block in as your static initializer.

Jonathan Gilbert
  • 3,526
  • 20
  • 28
0

Using a resource file and parsing it sounds like your best option. It won't be slow and wasteful if you

  1. parse the file line by line instead of loading the whole file at once and
  2. use caching on the dictionary in your application so you don't have to keep reloading it

You can get the CSV file to parse from here so you don't have to "type them in". And you can use this solution to parse it. The main advantage of doing it this way is that you can update the file easily when it changes.

Even if you don't agree this approach is best for you, you can use similar code to parse the file and use it to generate the C# code that initializes the Dictionary so you have it "compiled and ready".

Community
  • 1
  • 1
NightOwl888
  • 55,572
  • 24
  • 139
  • 212
0

Is there a logical and well-known design pattern for dealing with this data problem?

If I understand what you're asking correctly, this question is basically "is there a general-case, well-known paradigm for a program reading bytes from its own compiled binary and then using that as data during its execution?"

The answer to that is no. There are cases where it can be done, but in general, you can't assume that you're okay to do things like that unless you know that the executable file format won't be upset with what (to it) are a bunch of random bytes, whether the program loader on your OS will lock the file, preventing you from doing a read on it, etc.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85