0
 class Statistics
{
    Dictionary<decimal, Statistic> BabyDataStandardAgeHeadCircumference;
    Dictionary<decimal, Statistic> BabyDataStandardAgeLength;
    Dictionary<decimal, Statistic> BabyDataStandardAgeWeight;
    Dictionary<decimal, Statistic> BabyDataStandardWeightForLength;


}

These data are fixed - readonly and i want to load them from the database. The problem is

  1. How to make them readonly ?(i know through properties)
  2. How to fill them with data at program startup ?

Calling a method like Statistics.load() from startup event seems poor to me..

digEmAll
  • 56,430
  • 9
  • 115
  • 140
GorillaApe
  • 3,611
  • 10
  • 63
  • 106

6 Answers6

4

If you make them readonly or use properties, the dictionaries themselves will still be modifiable. One option is to make them private and provide GetXXX methods to retrieve the values.

class Statistics
{
    private static Dictionary<decimal, Statistic> babyDataStandardAgeHeadCircumference;
    private static Dictionary<decimal, Statistic> babyDataStandardAgeLength;
    private static Dictionary<decimal, Statistic> babyDataStandardAgeWeight;
    private static Dictionary<decimal, Statistic> babyDataStandardWeightForLength;

    static Statistics() 
    {
        // Put code to load from database here.  Will get called *once* when 
        // the *class* is first initialized.
    }

    public Statistic GetBabyDataStandardAgeHeadCircumfrence(decimal val) 
    {
        return babyDataStandardAgeHeadCircumfrence[val];
    }

    ...
}
Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
  • 2
    Terrible idea to put code that connects to a database in a static class constructor. If it fails, you cannot recover aside from killing the process and starting it anew. – quentin-starin Oct 12 '10 at 15:37
  • 1
    @qstarin, if you fail to connect to the database, your problems are already very serious. How do you plan to "recover" from a disconnected database? – Kirk Woll Oct 12 '10 at 15:38
  • +1 You want to wrap the dictionaries with Get methods so you don't accidentally modify them in the future.You could also set them as readonly and set them in the constructor instead of making them static. – Rex Morgan Oct 12 '10 at 15:39
  • 2
    @Kirk Woll: Try again. Ask the user for different connection params. Fail over to a backup database. Lots of different ways, which I have put into production, and in some cases that was to correct exactly the problem your example creates. Try a long-running service that glitches the first time that static ctor is hit. A lot easier to handle with instances and action policies that retry. Speaking from experience. – quentin-starin Oct 12 '10 at 15:46
  • @Kirk Woll: Not to mention how this completely eliminates the ability to unit test this. – quentin-starin Oct 12 '10 at 15:47
  • @qstarin, you can do *all* of those things like retrying and failing over *within the body of the static constructor,* so your point is moot. "Ask the user for different connection params"? Are you serious? What "production" system have you tried that? – Kirk Woll Oct 12 '10 at 16:04
  • @Kirk Woll: Got the blinders on pretty tight, eh? Well, have fun with your static ctors then. – quentin-starin Oct 12 '10 at 16:22
1

Making it read-only: make yourself a wrapper class implementing IDictionary in a read-only manner.

Initializing upon application start-up:

  • If you do need precise order of initialization operations, the Statistics.Load() approach isn't anything odd. Also, this gives you a reasonable room for error handling in case of database connection failures.
  • If you don't have to care of order of initialization, use a static constructor. By following this approach you'll have to make sure the database is accessible (in other words, there won't be any legitimate error situations) and that the first use of the class (which actually triggers the static constructor) isn't “too soon”.
Ondrej Tucny
  • 27,626
  • 6
  • 70
  • 90
1

Question:

How to make them readonly ?(i know through properties)

Answer: Rather than using a Dictionary<decimal, Statistics>, think about using an immutable wrapper for the dictionary.

SO link for an implementation of an immutable Dictionary class here:

Does C# have a way of giving me an immutable Dictionary?

Question:

How to fill them with data at program startup ?

Answer: Rather than fill them with data at program startup, how about filling them at the first access to the class (static or instanced)? This would mean populating these dictionaries in the static constructor (naturally the dictionaries would have to be static members as well).

public class Statistics
{
    public static readonly ImmutableDictionary<decimal, Statistic> 
        BabyDataStandardAgeHeadCircumference;
    public static readonly ImmutableDictionary<decimal, Statistic> 
        BabyDataStandardAgeLength;
    public static readonly ImmutableDictionary<decimal, Statistic> 
        BabyDataStandardAgeWeight;
    public static readonly ImmutableDictionary<decimal, Statistic> 
        BabyDataStandardWeightForLength;

    static Statistics()
    {
        // populate the dictionaries here...
    }
}
Community
  • 1
  • 1
code4life
  • 15,655
  • 7
  • 50
  • 82
0

Make a class that can create, load, and return your Statistics class, I would expose the method that does so through an interface:

public interface IStatisticsRepository {
    Statistics GetStatistics();
}

public class StatisticsRepository : IStatisticsRepository {

    private Statistics _statistics = null;

    private void LoadStatistics() {
         _statistics = GetFromDBHere();
    }

    public Statistics GetStatistics() {
        if (_statistics == null) {
            LoadStatistics();
        }

        return _statistics;

}

Then, your implementation of that interface is a service that can be used wherever. I'd inject it anywhere you need to get your statistics.

quentin-starin
  • 26,121
  • 7
  • 68
  • 86
  • *either* StatisticsRepository is only used by a single thread (or created whenever you need it), or your code is not thread-safe. If the former, initialization will happen far more often than *once*, as the OP required. – Kirk Woll Oct 12 '10 at 15:46
  • There's no requirement in the OP to grab the data from the DB only once. And if you call this "not thread-safe", you have an odd definition of thread safe. This instance cannot possibly enter an invalid state, the worst it could do is retrieve data more than once if multiple threads raced into the initialization. – quentin-starin Oct 12 '10 at 16:24
0

Actually, the properties you listed are collections based on the Dictionary class. The management (Add(), Remove(), [] indexer) of objects in a Dictionary is accessible by any instance that can see the BabyData... objects. In other words, you cannot make them read-only because the Dictionary class does not support that mode of operation via properties. You would have to declare the Dictionary as private and then interface each one via methods. This is the "dirty" approach.

OR, you can create a class based on the Dictionary class that controls the addition of objects via overloading. This is more complicated, but more in tune with what you are needing (from what I can understand).

As far as loading from the database, you'd need to tell us how you are able to fetch data from the database (via Sql, Linq to Sql, DataSet table adapters, etc.) to determine what is the best method for fetching the data into your Dictionary collections.

Michael
  • 3,821
  • 2
  • 19
  • 18
0

You could make the Statistics class follow the Singleton Pattern; and in the Instance property get create an instance if one is not already created:

class Statistics
{
    private static Statistics sInstance;
    private static Object sInstanceLock = new Object();
    private Statistics() {
        // Load data from database here...
    }
    public static Statistics Instance {
        get {
            lock(sInstanceLock) {
                if(sInstance == null) {
                    sInstance = new Statistics();
                }
                return sInstance;
            }
        }
    }
}

This would mean initialization would not necessarily have to take place at startup, although you could by invoking the Instance property at startup.

As for the read-only aspects I am not sure what your requirements are. If you mean that no one would be able to change the dictionary (add an element, remove an element) you could look at the answer to the question here: Immutable Dictionary. If you mean that no one can change the object that is stored as the value at a particular entry in the dictionary, then you would have to make the class or value type that is stored there immutable, the String class in .Net is an example of this.

Community
  • 1
  • 1
Steve Ellinger
  • 3,957
  • 21
  • 19