如何通过显式指定参数类型找到 IEnumerable<T>.ToList() 方法,然后使用自定义参数类型调用它

问题描述 投票:0回答:1

假设我们有以下代码(对我自己的代码进行了高度简化的修改):

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace ReflectionTest
{
    public interface IDataContext
    { }

    sealed class DataContext : IDataContext
    { }

    public interface ITable<T> : IEnumerable<T>
        where T : class
    {
        List<T> source { get; }
    }


    sealed class Table<T> : ITable<T>
        where T : class, new()
    {
        public Table()
        {
            source = new List<T>() { new T() };
        }

        public List<T> source { get; set; }

        public IEnumerator<T> GetEnumerator() => source.GetEnumerator();

        IEnumerator IEnumerable.GetEnumerator() => source.GetEnumerator();
    }

    public static class DataExtensions
    {
        public static ITable<T> GetTable<T>(this IDataContext dataContext)
            where T : class, new()
        {
            return new Table<T>();
        }
    }

    public class TestData
    {
        public string Name = "Test";
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            var dataContext = new DataContext();

            //var ret = dataContext.GetTable<TestData>().ToList(); but via reflection:
            var getTableMethod = typeof(DataExtensions).GetMethod("GetTable", new[] { typeof(IDataContext) });
            var getTableGeneric = getTableMethod.MakeGenericMethod(typeof(TestData));
            var testDataITable = getTableGeneric.Invoke(null, new object[] { dataContext });

            //var toListMethod = typeof(Enumerable).GetMethod("ToList", new[] { typeof(IEnumerable) });   this doesn't find IEnumerable<T>.ToList() method!
            var toListMethod = typeof(Enumerable).GetMethod("ToList");
            var toListGeneriс = toListMethod.MakeGenericMethod(testDataITable.GetType());

            //System.ArgumentException: 'Unable to cast object of type "ReflectionTest.Table`1[ReflectionTest.TestData]"
            //to type "System.Collections.Generic.IEnumerable`1[ReflectionTest.Table`1[ReflectionTest.TestData]]".'
            var ret = toListGeneriс.Invoke(null, new object[] { testDataITable });

            Console.ReadKey();
        }
    }
}

我试图通过反射来调用

var ret = dataContext.GetTable<TestData>().ToList();
。我这里有两个问题:

  1. typeof(Enumerable).GetMethod("ToList", new[] { typeof(IEnumerable) });
    找不到 IEnumerable.ToList() 方法。我知道这种方法只有一个版本,我可以简单地使用
    typeof(Enumerable).GetMethod("ToList");
    - 但是,如何通过显式指定参数类型来找到它?
  2. 如何使用
    ITable<TestData>
    参数类型正确调用此方法?使用我的代码我得到一个例外:

System.ArgumentException:'无法转换类型的对象 “ReflectionTest.Table

1[ReflectionTest.TestData]" to type System.Collections.Generic.IEnumerable
1[ReflectionTest.Table`1[ReflectionTest.TestData]]

谢谢你。

c# linq reflection ienumerable
1个回答
0
投票

对于第一个问题,您可以使用

Type.MakeGenericMethodParameter
创建一个“类型参数”,并使用它来创建代表
Type
IEnumerable<TSource>
。将其传递给
GetMethod
将为您提供所需的方法。

var typeVariable = Type.MakeGenericMethodParameter(0);
var parameterType = typeof(IEnumerable<>).MakeGenericType(typeVariable)
var toListMethod = typeof(Enumerable).GetMethod("ToList", [parameterType]);

对于第二个问题,是因为你参数化

ToList
不正确。您应该使用集合的元素类型 -
TestData
:

var toListGeneriс = toListMethod.MakeGenericMethod(typeof(TestData));
© www.soinside.com 2019 - 2024. All rights reserved.