2

I'm developing scientific software that needs access to the periodic table of elements. An Element comprises of a set of Isotopes which have a few readonly properties (e.g. mass, abundance, atomic number, etc.). There are over 100 elements, and when factoring in their isotopes, there are well over 1000 isotopes. To populate all these objects at run time, I currently have an XML file (Build Action: Content)* containing all the elemental data that I parse in during the static constructor of the Element class:

public class Element {

    private static readonly Dictionary<string, Element> _elements;

    static Element()
    {
        _elements = new Dictionary<string, Element>();            
        LoadElements("Resources/Elements.xml");  // 461 KB file    
    }

    static LoadElements(string resource) {
         // code for construction of elements objects and population of the 
         // _elements dictionary.
    }      

    private Element(blah) { \\ instance constructor }

}

This works, but there is a overhead in parsing in the file and I lose some flexibility in designing the Element class. The alternative is to hard-code each Isotope and Element into the static constructor. The advantage of the later is I would be able to add static readonly property for each Element (a useful feature):

 public class Element {

    private static readonly Dictionary<string, Element> _elements;

    public static readonly Element Carbon = {get; private set;}
    public static readonly Element Hydrogen = {get; private set;}

    static Element()
    {
        _elements = new Dictionary<string, Element>();  

        Carbon = AddElement("Carbon", 6);  
        Carbon.AddIsotope(12, 12.0000000, 0.9893);
        Carbon.AddIsotope(13, 13.0033548378, 0.0107);

        Hydrogen = AddElement("Hydrogen", 1);
        //Repeat this pattern for all the elements...
    }

    static Element AddElement(string name, double atomicNumber) 
    {
          Element element = new Element(name, atomicNumber);
          _elements.Add(name, element);
          return element;
    }

    private Element(string name, double atomicNumber) {
         // Not Important, just setting readonly properties
    }

    private void AddIsotope(int massNumber, double mass, double abundance) {
         // Not Important;
    }

}

However, this seems like a lot of hard-coded data to include in a class.cs file. So I am torn, on one hand it makes sense on a data management level to have the elemental data stored in an external file which is read in. But on the other hand, because all the data is really a bunch of constant/static readonly objects, this additional parsing work seems timely, unfruitful, and limits the API design. What is the correct way for creating all these objects?

*Note: the Build Action is set to Content for the case if the client wants to modify the values of the elements for whatever reason. This isn't a necessity and could be changed to an embedded resource.

Moop
  • 3,414
  • 2
  • 23
  • 37
  • can you put the values in a database? – Beth Feb 04 '13 at 19:21
  • 1
    External files is the way to go. Never hardcode anything of this sort, especially if the user may some day want to change it. – Artless Feb 04 '13 at 19:21
  • 1
    Another option would be to use [T4](http://msdn.microsoft.com/en-us/library/vstudio/bb126445.aspx) to actually generate C# code FROM the XML file at design time. This would save you the manual work of writing the C# yourself, save the time it takes at runtime to parse the XML file, and would also give you the ability to change it quickly in the future. – Federico Berasategui Feb 04 '13 at 19:25
  • So each element has the same static readonly Elements (e.g. Carbon and Hydrogen) ? – paparazzo Feb 04 '13 at 19:39
  • These are fundamental constants that *never* change as long as the code is confined to the Solar system. Sure you can hard-code them. – Hans Passant Feb 04 '13 at 19:39
  • @HansPassant more like the Universe. The only reason they would change is if we can experimentally get better precision on their values (i.e. more significant digits). The data comes from the de facto source on such matters (http://www.nist.gov/pml/data/comp.cfm). So that is why I was considering hard coding them, since they are the closest things to real universal, fundamental constants. – Moop Feb 04 '13 at 19:46
  • @Blam It is like any other static property, you access them through the class declaration (`Element.Carbon`) not through an instance (`Element c; c.Carbon;` wouldn't work) – Moop Feb 04 '13 at 19:54
  • @HighCore T4 seems like an elegant solution to this. Design-time benefits with data maintainability. – Moop Feb 04 '13 at 19:55
  • OK I think I follow. If you are reading in maybe create just one set of static elements. But then you lose static properties. Hard coding might be the way to go. – paparazzo Feb 04 '13 at 20:09

2 Answers2

3

I would consider putting the values in an embedded file, but possibly having an enum of the elements. (Probably not the isotopes, but provide an easy way of specifying an isotope from the elements.)

That way:

  • You can still have a strongly-typed API, and not rely on magic strings etc in user code
  • You can still make it easy to change the data later should you really wish to (and possibly supply a way of reading the data from an external source)
  • You probably make it easier to work with the data itself, as an XML file rather than C#

Don't worry about the parsing work - given that you only need to do it once, I find it hard to believe that it would be significant in terms of performance.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I agree that the magic strings aren't the best, and the enum could work in its place. @HighCore has a good potential solution with T4, what are your thoughts on this? Isotopes are easy to deal with, I have an indexer in `Element` that takes an `int` (corresponding to the mass number). e.g. `Element carbon; Isotope c13 = carbon[13];` – Moop Feb 04 '13 at 19:59
  • I moved to a SAX `XmlTextReader` to improve the parsing speed. – Moop Feb 10 '13 at 21:08
0

Check out the blue obelisk project which is hosted on sourceforge - I think you'll find some useful stuff there, possibly even exactly what you're looking for.

Drew Gibson
  • 1,624
  • 3
  • 18
  • 22