0

FYI: the verbose preamble is to help explain why I am using Activator.CreateInstance. I have a number of entities (objects corresponding to database column information) that are "contained" in multiple databases, each of which has a different table/column setup. So I am able to retrieve an entity from each database, but the way I retrieve it is different per database. The database type is not known till runtime and could vary throughout execution. I have created the following setup:

First define the query operations each entity should support and each entity reader should support these operations.

public abstract class Operations<T> {
    public delegate T findDelegate(int id);
    public findDelegate find;
}

// there are many of these N=1,2,..., but here is one
// use abstract class since implementation of queries should be done by handlers
public class EntityNReader : Operations<EntityN> {
    public Reader();
}

Define an interface for "Handler" classes, i.e. these classes implement the query operations listed above.

public interface IHandler<T> {
    public string find(int id);
}

// there are many of these N,M=1,2..., but here is one
// use of interface is to force handlers to implement all query types
public class EntityNHandlerForDbTypeM : IHandler<EntityN> {
    public string find(int id) {/*whatever*/}
}

This allows the developers to create a single class for handling EntityN query operations for DbTypeM. Now, create a Database class that contains the reader objects and binds the handler methods to the reader delegates.

public class Database {
    // there are many of these, but here is one
    public EntityNReader EntitiesN;

    public Database(string dbType) {
        // this is called for each EntityNReader
        bindHandlers<Reader, TypeN>(MyReader, dbType);
        // ...

        // nullreferenceexception
        EntitiesN.find(0);
    }

    // this is a factory that also performs late binding
    private void bindHandlers<T,K>(T reader, string dbTypeM)
        where T: Operations<K>, new()
    {
        // create instance of EntityNReader
        r = (T)Activator.CreateInstance(typeof(T));
        // r != null

        // create instance of handler
        IHandler<K> h = (IHandler<K>)(Activator.CreateInstance(
            Type.GetType("namespace.to.EntityNHandlerForDbTypeM"),
            new object[] { this }
        ));

        // bind delegates
        r.find = h.find;
    }
}

As you can see in Databases constructor, the way the code is written now, I get a NullReferenceException even though instance r of EntityNReader is created and (verified to be) not null.

However, if I instantiate EntitiesN where it is declared in Database instead of within bindHandlers, the code compiles and everything works. The reason I don't just do this is that (subsequently) I would like to conditionally create readers/handlers inside of bindHandlers at the time the Database class is instantiated.

What is happening here? Link to actual code if necessary. P.S. I am relatively new to programming, so I am open to hearing how an experience developer might design this component (especially if I am heading down the wrong path).

jayflo
  • 1,105
  • 1
  • 12
  • 21

1 Answers1

0

I realize your code was just samples, but I spotted this right off the bat...

if (supports[typeof(Entity1).Name]) { bindHandlers<Entity1Reader, Entity1>(Entities1, CamaDbType); }
if (supports[typeof(Entity2).Name]) { bindHandlers<Entity1Reader, Entity1>(Entities1, CamaDbType); }

Is it possible that you have a simple copy/paste mistake? Notice that Entities1 is passed in for both bindHandlers calls.

Trevor Ash
  • 623
  • 4
  • 8
  • No sorry. I noticed that, fixed it and just hadn't pushed the changes to github yet (sorry). The question above came after I made the change. I just pushed the changes. – jayflo Nov 03 '14 at 14:19