D
dsmith
I have a class to store a data array and associated metadata, and the
array can be constructed either as (for illustrative purposes) float
or short. I would like to convert this to a generic version of the
class to avoid a lot of extra type checking throughout the class, and
speed up certain functions (testing using a fixed version of the
generic class showed a 20%-30% improvement in certain high-cost
functions).
So, the current version is:
public class DataArray
{
public DataArray(int rows, int cols, Type dataType)
{
switch (dataType)
case typeof(float):
localArray = new float[rows,cols];
break;
case typeof(short):
localArray = new short[rows,cols];
break;
}
}
}
And I would like to instead have:
public class DataArray<TArrayType>
{
public DataArray(int rows, int cols)
{
localArray = new TArrayType[rows, cols];
}
}
So far easy enough. However to allow data to be assigned from one
array to another I had to add a construction restriction:
public class DataArray<TArrayType> where TArrayType : IConvertible
{
public DataArray(int rows, int cols)
{
localArray = new TArrayType[rows, cols];
}
public TArrayType this[int row, int col]
{
get
{
return localArray[row, col];
}
set
{
localArray[row, col] = value;
}
}
}
I would have preferred to be able to specify the exact allowable
types, but I can filter further in the constructor. Unfortunately the
compiler gets touchy about it in various places.
So now I'd like to do some math. DataArray 1 (da1) and DataArray 2
(da2) can be of either float or short, and the result of some
calculation on the cells of each array will be put in DataArray 3
(da3); I know what type da3 is going to be, so that isn't a problem.
First I need to get da1 and da2 from the objects that are holding onto
them. And.... now I'm stuck. How to I define variables for generic
versions (ie: determined at run-time) of the DataArray? What does a
function that can return any type of DataArray look like?
Various attempts:
DataArray da1; // Using the generic type 'DataArray<TArrayType>'
requires '1' type arguments
DataArray<float> da1; // Well fine, it compiles, but now I'm locked
into using a specific type of DataArray, which is contrary to the
entire point of making it generic in the first place. Instead of type
checking inside the class as is done now, I just move the type
checking burden to outside the class.
Other error messages lead me to try
DataArray<IConvertible> da1; // It compiles!
DataArray<float> da2 = new DataArray<float>(1,2); // Assuming I can
get a function to return this, this is what we'll be assigning to da1.
da1 = da2 // Cannot implicitly convert type 'DataArray<float>' to
'DataArray<System.IConvertible>' --- ?? What? Ok, maybe an explicit
conversion...
da1 = (DataArray<IConvertible>)new DataArray<float>(1, 1); // Cannot
convert type 'DataArray<float>' to 'DataArray<System.IConvertible>'
--- Ok, not that way either.
And on top of this is trying to figure out a method signature that
will return a generic version of DataArray:
private DataArray<V> GetGenDA(int i)
{
if (i == 1)
return new GenericDataArray<float>();
else
return new GenericDataArray<short>();
}
// The type or namespace name 'V' could not be found (are you missing
a using directive or an assembly reference?)
And if I drop the <V> I get:
// Using the generic type 'DataArray<TArrayType>' requires '1' type
arguments
Another possibility: perhaps I can return the type of array contained
in each container object and use that to define the variables that are
going to accept the arrays.
private Type GetTypeOfDocument()
{
// example:
return typeof(DataArray<float>);
}
private void SomeOtherFunction()
{
Type docType = GetTypeOfDocument();
docType da1; // The type or namespace name 'docType' could not be
found (are you missing a using directive or an assembly reference?)
}
Or perhaps using reflection:
private Type GetDataArrayType()
{
return typeof(short);
}
private void MakeDAObject()
{
Type da1 = typeof(DataArray<>);
Type da1a = da1.MakeGenericType(GetDataArrayType());
// Fine up to here, where once again we can only create an instance
if we know the concrete type
// beforehand.
da1a da2 = (da1a)Activator.CreateInstance(da1a);
}
So in the end, nothing seems to work. Is what I'm trying to do at all
possible? It would seem to apply to any situation where you want to
consume/manipulate a generic object rather than perform work within
the scope that the generic was originally declared, or within the
generic object itself. Every time I think I've figured something out,
it just turns out that the problem got shifted one level up or down in
the code.
David
array can be constructed either as (for illustrative purposes) float
or short. I would like to convert this to a generic version of the
class to avoid a lot of extra type checking throughout the class, and
speed up certain functions (testing using a fixed version of the
generic class showed a 20%-30% improvement in certain high-cost
functions).
So, the current version is:
public class DataArray
{
public DataArray(int rows, int cols, Type dataType)
{
switch (dataType)
case typeof(float):
localArray = new float[rows,cols];
break;
case typeof(short):
localArray = new short[rows,cols];
break;
}
}
}
And I would like to instead have:
public class DataArray<TArrayType>
{
public DataArray(int rows, int cols)
{
localArray = new TArrayType[rows, cols];
}
}
So far easy enough. However to allow data to be assigned from one
array to another I had to add a construction restriction:
public class DataArray<TArrayType> where TArrayType : IConvertible
{
public DataArray(int rows, int cols)
{
localArray = new TArrayType[rows, cols];
}
public TArrayType this[int row, int col]
{
get
{
return localArray[row, col];
}
set
{
localArray[row, col] = value;
}
}
}
I would have preferred to be able to specify the exact allowable
types, but I can filter further in the constructor. Unfortunately the
compiler gets touchy about it in various places.
So now I'd like to do some math. DataArray 1 (da1) and DataArray 2
(da2) can be of either float or short, and the result of some
calculation on the cells of each array will be put in DataArray 3
(da3); I know what type da3 is going to be, so that isn't a problem.
First I need to get da1 and da2 from the objects that are holding onto
them. And.... now I'm stuck. How to I define variables for generic
versions (ie: determined at run-time) of the DataArray? What does a
function that can return any type of DataArray look like?
Various attempts:
DataArray da1; // Using the generic type 'DataArray<TArrayType>'
requires '1' type arguments
DataArray<float> da1; // Well fine, it compiles, but now I'm locked
into using a specific type of DataArray, which is contrary to the
entire point of making it generic in the first place. Instead of type
checking inside the class as is done now, I just move the type
checking burden to outside the class.
Other error messages lead me to try
DataArray<IConvertible> da1; // It compiles!
DataArray<float> da2 = new DataArray<float>(1,2); // Assuming I can
get a function to return this, this is what we'll be assigning to da1.
da1 = da2 // Cannot implicitly convert type 'DataArray<float>' to
'DataArray<System.IConvertible>' --- ?? What? Ok, maybe an explicit
conversion...
da1 = (DataArray<IConvertible>)new DataArray<float>(1, 1); // Cannot
convert type 'DataArray<float>' to 'DataArray<System.IConvertible>'
--- Ok, not that way either.
And on top of this is trying to figure out a method signature that
will return a generic version of DataArray:
private DataArray<V> GetGenDA(int i)
{
if (i == 1)
return new GenericDataArray<float>();
else
return new GenericDataArray<short>();
}
// The type or namespace name 'V' could not be found (are you missing
a using directive or an assembly reference?)
And if I drop the <V> I get:
// Using the generic type 'DataArray<TArrayType>' requires '1' type
arguments
Another possibility: perhaps I can return the type of array contained
in each container object and use that to define the variables that are
going to accept the arrays.
private Type GetTypeOfDocument()
{
// example:
return typeof(DataArray<float>);
}
private void SomeOtherFunction()
{
Type docType = GetTypeOfDocument();
docType da1; // The type or namespace name 'docType' could not be
found (are you missing a using directive or an assembly reference?)
}
Or perhaps using reflection:
private Type GetDataArrayType()
{
return typeof(short);
}
private void MakeDAObject()
{
Type da1 = typeof(DataArray<>);
Type da1a = da1.MakeGenericType(GetDataArrayType());
// Fine up to here, where once again we can only create an instance
if we know the concrete type
// beforehand.
da1a da2 = (da1a)Activator.CreateInstance(da1a);
}
So in the end, nothing seems to work. Is what I'm trying to do at all
possible? It would seem to apply to any situation where you want to
consume/manipulate a generic object rather than perform work within
the scope that the generic was originally declared, or within the
generic object itself. Every time I think I've figured something out,
it just turns out that the problem got shifted one level up or down in
the code.
David