使用动态类型调用泛型方法 (.net 3.5)
我正在尝试调用类上的方法来对调用该方法之前未知的数据类型的数据进行排序。
以下是尝试调用通用方法的排序过程的代码:
public void Sort(LiteTableColumn column, LiteSortOrder sortOrder)
{
column.Sort(sortOrder);
//create an array of the values
object[] values = new object[_rowCount];
for (int i = 0; i < _rowCount; i++)
{
values[i] = this.GetValue(column.Index, i);
}
Type sortType = typeof(QuickSort<>);
Type constructedClass = sortType.MakeGenericType(Type.GetType("System." + column.DataType));
object created = Activator.CreateInstance(constructedClass);
_sortKey = (int[])sortType.GetMethod("Sort").MakeGenericMethod(Type.GetType("System." + column.DataType)).Invoke(constructedClass, new object[] { values });
}
我在这一行收到错误:
_sortKey = (int[])sortType.GetMethod("Sort").MakeGenericMethod(Type.GetType("System." + column.DataType)).Invoke(constructedClass, new object[] { values });
错误:
{"Int32[] Sort(T[], Test_SQL_Stream.LiteObjects.LiteSortOrder) is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true."}
我不确定为什么会发生这种情况。难道是因为我的 QuickSort 类有 T : IComparable
吗?
这是 QuickSort 类
public class QuickSort<T> where T : IComparable
{
/// <summary>
/// Sorts a given array of data in an ascending/descending fashion
/// </summary>
public QuickSort()
{
}
/// <summary>
/// Sorts the items in an order specifies & returns an index that reflects the sorted values
/// </summary>
/// <param name="sortArray">The array of values to sort (must implement IComparable)</param>
/// <param name="direction">The order to sort. Unsorted is not a valid parameter</param>
/// <returns></returns>
public int[] Sort(T[] sortArray, LiteSortOrder direction)
{
int rows = sortArray.Length;
int[] index = new int[rows];
//populate the index
for (int i = 0; i < rows; i++)
{
index[i] = i;
}
//raise an error in case the sort direction is set at unsorted and return the original list
if (direction == LiteSortOrder.Unsorted)
{
new InvalidOperationException("Unable to sort items in: LiteSortOrder.Unsorted order");
return index;
}
//sort the values
quickSort(sortArray, index, 0, rows - 1);
//if it should be descending order, reverse the items order
if (direction == LiteSortOrder.Descending)
{
int t;
int i1 = 0;
int i2 = rows - 1;
while (i1 < i2)
{
t = index[i1];
index[i1] = index[i2];
index[i2] = t;
i1++;
i2--;
}
}
//return the sorted index
return index;
}
private static void quickSort(T[] List, int[] RefList, int StartIdx, int EndIdx)
{
int Lo, Hi, T;
T Mid;
Lo = StartIdx;
Hi = EndIdx;
Mid = List[RefList[(Lo + Hi) / 2]];
do
{
while (List[RefList[Lo]].CompareTo(Mid) < 0) Lo++;
while (List[RefList[Hi]].CompareTo(Mid) > 0) Hi--;
if (Lo <= Hi)
{
T = RefList[Lo];
RefList[Lo] = RefList[Hi];
RefList[Hi] = T;
Lo++;
Hi--;
}
} while (Lo <= Hi);
if (Hi > StartIdx) quickSort(List, RefList, StartIdx, Hi);
if (Lo < EndIdx) quickSort(List, RefList, Lo, EndIdx);
}
}
编辑:所以在关于使用 Array.Sort 的评论之后,我进一步研究了这个方法。它比我的快速排序方法(我使用字符串而不是泛型进行测试)快得多:
对于那些想知道的人,这里是结果:
Populate Strings:159ms
Populate Objects: 53ms
Array.Sort w/Key: 10ms
Array.Sort w/o Key: 229ms
QuickSort w/strings: 231ms
和代码:
watch.Start();
string[] values = new string[_rowCount];
for (int i = 0; i < _rowCount; i++)
{
if (this.GetValue(column.Index, i) != null)
values[i] = this.GetValue(column.Index, i).ToString();
else
values[i] = "";
}
Debug.WriteLine("Populate Strings:" +watch.ElapsedMilliseconds.ToString());
watch.Reset();
watch.Start();
object[] objVal = new object[_rowCount];
for (int i = 0; i < _rowCount; i++)
{
_sortKey[i] = i;
objVal[i] = this.GetValue(column.Index, i);
}
Debug.WriteLine("Populate Objects: " + watch.ElapsedMilliseconds.ToString());
watch.Reset();
watch.Start();
Array.Sort(_sortKey, objVal);
Debug.WriteLine("Array.Sort w/Key: " + watch.ElapsedMilliseconds.ToString());
watch.Reset();
watch.Start();
Array.Sort(objVal);
Debug.WriteLine("Array.Sort w/o Key: " +watch.ElapsedMilliseconds.ToString());
watch.Reset();
watch.Start();
QuickSort sorter = new QuickSort();
sorter.Sort(values, LiteSortOrder.Ascending);
Debug.WriteLine("QuickSort w/strings: " + watch.ElapsedMilliseconds.ToString());
I am trying to call a method on a class to sort data of a datatype that is unknown until the method is called.
Here is the code for the sort procedure that tries to call the generic method:
public void Sort(LiteTableColumn column, LiteSortOrder sortOrder)
{
column.Sort(sortOrder);
//create an array of the values
object[] values = new object[_rowCount];
for (int i = 0; i < _rowCount; i++)
{
values[i] = this.GetValue(column.Index, i);
}
Type sortType = typeof(QuickSort<>);
Type constructedClass = sortType.MakeGenericType(Type.GetType("System." + column.DataType));
object created = Activator.CreateInstance(constructedClass);
_sortKey = (int[])sortType.GetMethod("Sort").MakeGenericMethod(Type.GetType("System." + column.DataType)).Invoke(constructedClass, new object[] { values });
}
I am getting an error on this line:
_sortKey = (int[])sortType.GetMethod("Sort").MakeGenericMethod(Type.GetType("System." + column.DataType)).Invoke(constructedClass, new object[] { values });
Error:
{"Int32[] Sort(T[], Test_SQL_Stream.LiteObjects.LiteSortOrder) is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true."}
I'm not sure why exactly this is happening. Could it be because my QuickSort class has T : IComparable
?
Here is the QuickSort class
public class QuickSort<T> where T : IComparable
{
/// <summary>
/// Sorts a given array of data in an ascending/descending fashion
/// </summary>
public QuickSort()
{
}
/// <summary>
/// Sorts the items in an order specifies & returns an index that reflects the sorted values
/// </summary>
/// <param name="sortArray">The array of values to sort (must implement IComparable)</param>
/// <param name="direction">The order to sort. Unsorted is not a valid parameter</param>
/// <returns></returns>
public int[] Sort(T[] sortArray, LiteSortOrder direction)
{
int rows = sortArray.Length;
int[] index = new int[rows];
//populate the index
for (int i = 0; i < rows; i++)
{
index[i] = i;
}
//raise an error in case the sort direction is set at unsorted and return the original list
if (direction == LiteSortOrder.Unsorted)
{
new InvalidOperationException("Unable to sort items in: LiteSortOrder.Unsorted order");
return index;
}
//sort the values
quickSort(sortArray, index, 0, rows - 1);
//if it should be descending order, reverse the items order
if (direction == LiteSortOrder.Descending)
{
int t;
int i1 = 0;
int i2 = rows - 1;
while (i1 < i2)
{
t = index[i1];
index[i1] = index[i2];
index[i2] = t;
i1++;
i2--;
}
}
//return the sorted index
return index;
}
private static void quickSort(T[] List, int[] RefList, int StartIdx, int EndIdx)
{
int Lo, Hi, T;
T Mid;
Lo = StartIdx;
Hi = EndIdx;
Mid = List[RefList[(Lo + Hi) / 2]];
do
{
while (List[RefList[Lo]].CompareTo(Mid) < 0) Lo++;
while (List[RefList[Hi]].CompareTo(Mid) > 0) Hi--;
if (Lo <= Hi)
{
T = RefList[Lo];
RefList[Lo] = RefList[Hi];
RefList[Hi] = T;
Lo++;
Hi--;
}
} while (Lo <= Hi);
if (Hi > StartIdx) quickSort(List, RefList, StartIdx, Hi);
if (Lo < EndIdx) quickSort(List, RefList, Lo, EndIdx);
}
}
EDIT: So after the comments about using Array.Sort, I looked into this method further. It is MUCH faster than my quicksort method (which I tested using strings instead of generics):
For those of you who would like to know, here are the results:
Populate Strings:159ms
Populate Objects: 53ms
Array.Sort w/Key: 10ms
Array.Sort w/o Key: 229ms
QuickSort w/strings: 231ms
and the code:
watch.Start();
string[] values = new string[_rowCount];
for (int i = 0; i < _rowCount; i++)
{
if (this.GetValue(column.Index, i) != null)
values[i] = this.GetValue(column.Index, i).ToString();
else
values[i] = "";
}
Debug.WriteLine("Populate Strings:" +watch.ElapsedMilliseconds.ToString());
watch.Reset();
watch.Start();
object[] objVal = new object[_rowCount];
for (int i = 0; i < _rowCount; i++)
{
_sortKey[i] = i;
objVal[i] = this.GetValue(column.Index, i);
}
Debug.WriteLine("Populate Objects: " + watch.ElapsedMilliseconds.ToString());
watch.Reset();
watch.Start();
Array.Sort(_sortKey, objVal);
Debug.WriteLine("Array.Sort w/Key: " + watch.ElapsedMilliseconds.ToString());
watch.Reset();
watch.Start();
Array.Sort(objVal);
Debug.WriteLine("Array.Sort w/o Key: " +watch.ElapsedMilliseconds.ToString());
watch.Reset();
watch.Start();
QuickSort sorter = new QuickSort();
sorter.Sort(values, LiteSortOrder.Ascending);
Debug.WriteLine("QuickSort w/strings: " + watch.ElapsedMilliseconds.ToString());
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的
Sort
方法是泛型类上的非泛型方法。MakeGenericMethod
只能在泛型方法上调用 - 本身采用泛型参数的方法。一旦构造了封闭式通用
QuickSort
类型,Sort
就是一个普通方法。Your
Sort
method is a non-generic method on a generic class.MakeGenericMethod
can only be called on generic methods – methods that themselves take a generic parameter.Once you construct the closed generic
QuickSort<Something>
type,Sort
is a normal method.Sort
函数不是通用的。它只是在泛型类中,但它本身并不是泛型。因此:The
Sort
function is not generic. It is merely inside a generic class, but it is not generic itself. Hence: