使用动态类型调用泛型方法 (.net 3.5)

发布于 2024-12-17 11:36:49 字数 5414 浏览 3 评论 0原文

我正在尝试调用类上的方法来对调用该方法之前未知的数据类型的数据进行排序。

以下是尝试调用通用方法的排序过程的代码:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

忘年祭陌 2024-12-24 11:36:49

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

打小就很酷 2024-12-24 11:36:49

Sort 函数不是通用的。它只是在泛型类中,但它本身并不是泛型。因此:

 _sortKey = (int[])sortType.GetMethod("Sort").Invoke(constructedClass, new object[] { values });

The Sort function is not generic. It is merely inside a generic class, but it is not generic itself. Hence:

 _sortKey = (int[])sortType.GetMethod("Sort").Invoke(constructedClass, new object[] { values });
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文