tags:

views:

100

answers:

6

Hello.. I have this class

 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..

+4  A: 

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
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.
qstarin
@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
+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.
RexM
@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.
qstarin
@Kirk Woll: Not to mention how this completely eliminates the ability to unit test this.
qstarin
@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
@Kirk Woll: Got the blinders on pretty tight, eh? Well, have fun with your static ctors then.
qstarin
+1  A: 

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
A: 

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.

qstarin
@qstarin, *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
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.
qstarin
A: 
Michael
A: 

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.

Steve Ellinger
+1  A: 

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:

http://stackoverflow.com/questions/35002/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...
    }
}
code4life