简体   繁体   中英

Declaring an array of base class and instantiating inherited members

I have a class defined with a generic:

public class GenericDataStore<T>
{
     // UnderlyingDataStore is another class that manages a queue, or a linked list
     private UnderlyingDataStore<T> dataQueue = new UnderlyingDataStore<T>();
     public void addData(T data) { dataQueue.Add(data); }
     public T getLastData() { dataQueue.getLastData(); }
}

I then have different derived classes based on this class:

public class ByteDataStore : GenericDataStore<Byte>
{
}
public class DoubleDataStore : GenericDataStore<Double>
{
}
public class PObjDataStore : GenericDataStore<PObj> // PObj is another class declared somewhere
{
}

Then, I have a "Manager" class that looks like:

public class DataManager
{
     /* Here, I want to declare a 2 dim array [,] that holds pointers to the
        data stores. Depending on some other variables, the array may need
        to point to DoubleDataStore, ByteDataStore, etc. The following doesn't work,
        since GenericDataStore must be declared with a generic type: */

        GenericDataStore [,] ManagedDataStores; // Can not compile

        public DataManager() {
           for (int i=0; i<numStores; i++) {
               for (int j=0; j<numCopies; j++) {
                   // objType is a utility function that we have that returns a type
                   if (objType(i,j) == typeof(Byte)) {
                         ManagedDataStores[i,j] = new ByteDataStore();
                   } else if (objType(i,j) == typeof(double)) {
                         ManagedDataStores[i,j] = new DoubleDataStore();
                   }
               }
           }
        }

        void Add(int id, int copyid, Byte data) {
             ManagedDataStores[i,j].Add(data);
        }

}

There might be other, better ways to do this. Essentially, we want to have different data stores for different object types, which can be managed by a class. We want only this 'manager' class to be exposed to the user (like an API), and no direct access to the underlying classes.

Thanks in advance.

I'm afraid that this is one of those instances where Generic's don't help you one bit. By definition, you must know the generic type at compile time, rather than runtime. For runtime type-indiference, you need to do it the old-fashioned way.

public class DataStore
{
     // UnderlyingDataStore is another class that manages a queue, or a linked list
     private UnderlyingDataStore dataQueue = new UnderlyingDataStore();
     public void addData(object data) { dataQueue.Add(data); }
     public object getLastData() { dataQueue.getLastData(); }
}

This, has the obvious drawback of boxing/unboxing- as well as the need for calling-code to know what type's it should be dealing with in order to cast.

However, you could also use the other answer , as long as you're able to cast the managedDataStore to the correct generic type.

If you want to create and initialize the double dimensional array use this:

int numStores = 2;
int numCopies = 3;

//GenericDataStore<object>[,] managedDataStores = new GenericDataStore<object>[numStores,numCopies];
 Object[,] managedDataStores = new Object[numStores,numCopies];
for (int i = 0; i < numStores; i++)
{
   for (int j = 0; j < numCopies; j++)
   {
    managedDataStores[i,j] = new GenericDataStore<object>();
   }
}

I would add an interface and implement it explicitly to hide it from the class users:

internal interface GeneralDataStore
{
     void addData(object data);
     object getLastData();
}

public class GenericDataStore<T> : GeneralDataStore
{
     // UnderlyingDataStore is another class that manages a queue, or a linked list
     private UnderlyingDataStore<T> dataQueue = new UnderlyingDataStore<T>();
     public void addData(T data) { dataQueue.Add(data); }
     public T getLastData() { dataQueue.getLastData(); }

     object GeneralDataStore.getLastData() { return getLastData(); }
     void GeneralDataStore.addData(object data) { add((T)data); }
}

GeneralDataStore [,] ManagedDataStores;

This doesn't give you what you want, since it's impossible. But it give you some type safety.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM