【问题标题】:Reflection : How to get the result (and do foreach on it) from method invoked using Reflection?反射:如何从使用反射调用的方法中获取结果(并对其进行 foreach)?
【发布时间】:2017-05-25 08:10:24
【问题描述】:

我想从不同的存储库中调用一些方法并具有相同类型的 List<> 作为结果,但我不知道如何在没有硬代码的情况下转换结果以及如何在此结果上使用 foreach,这里下面的例子:

class Person
{
    public string Name { get; set; }
}

class Animal
{
    public string Name { get; set; }
}

class PersonRepository
{
    public List<Person> GetPersons()
    {
          List<Person> list = new List<Person>();

          //Some processing...

          return list;
    }
}

class AnimalRepository
{
    public List<Animal> GetAnimals()
    {
        List<Animal> list = new List<Animal>();

        //Some processing...

         return list;
    }
}

public class ReflectionClass
{
    public List<T> GetResultFromMethodInvoked<T>(string entityName, string repositoryName, string methodName)
    {
        List<T> lists = new List<T>();
        Type entity_type = Type.GetType("Entities." + entityName + " ,Entities");
        Type repository = Type.GetType("Crud." + repositoryName + ", Crud");
        MethodInfo method = repository.GetType().GetMethod(methodName);


        var r= method.Invoke(repository, parameters);


        Convert.ChangeType(r, typeof(List<>).MakeGenericType(new Type[] { entity_type }));

        lists = (List<T>)r;

        return lists;
    }
}

class Program
{
    static void Main(string[] args)
    {
        ReflectionClass reflection = new ReflectionClass();
        /* Should have List<Person> as RESULT */
        reflection.GetResultFromMethodInvoked("Person", "PersonRepository", "GetPersons");

        /* Should have List<Animal> as RESULT */
        reflection.GetResultFromMethodInvoked("Animal", "AnimalRepository", "GetAnimals");
    }
}

【问题讨论】:

  • 这是不可能的,你不能让编译器推断你在运行时提供的类型。您必须在编译时提供通用类型参数以使用强类型。
  • 但是,您当然可以将结果转换为非通用 IEnumerable-interface 并对其进行迭代。或者创建一个接口,列表中所有可能的类型都实现并转换为List&lt;TheInterface&gt;
  • 嗨@HimBromBeere,我不太清楚,我是C#的新手,你能举个例子吗?非常感谢

标签: c# reflection casting generic-list


【解决方案1】:

在您的代码中,您使用泛型 public List&lt;T&gt; GetResultFromMethodInvoked&lt;T&gt;(string entityName, string repositoryName, string methodName) 所以:

ReflectionClass reflection = new ReflectionClass();
/* Should have List<Person> as RESULT */
List<Person> result = reflection.GetResultFromMethodInvoked<Person>("Person", "PersonRepository", "GetPersons");

【讨论】:

    【解决方案2】:

    您不能作为编译器执行此操作,因为您不知道您的 runtime-string "Person" 表示 Person-type。你不能指望编译器推断出运行时提供的类型(例如通过它的名称)。

    所以你有三个选择。

    1. 您已经提到了这一点,将其转换为实际的列表类型,例如List&lt;Person&gt;
    2. 或者让列表可能包含的所有类型都继承自一个通用接口并转换为接口类型的列表

      interface MyInterface
      {
          public string Name { get; set; }
      }
      class Person : MyInterface
      {
          public string Name { get; set; }
      }
      class Animal : MyInterface
      {
          public string Name { get; set; }
      }
      

      现在使用您的列表界面:

      var result = reflection.GetResultFromMethodInvoked<MyInterface>("Person", "PersonRepository", "GetPersons");
      foreach(var o in result) 
          Console.WriteLine(o.Name);
      
    3. 完全省略强类型并使用非泛型 Enumerable-class 并迭代:

      var result = (Enumerable) reflection.GetResultFromMethodInvoked("Person", "PersonRepository", "GetPersons");
      foreach(var o in result) ...
      

      为此,您的方法当然也应该是非泛型的,因为在该方法之外您不能真正使用泛型类型。

    【讨论】:

    • @AbdelatifLatrach 正如我已经说过的那样,一个 geeric 类型参数(括号内的东西,(MyType) result 或 DoSomething()` 是 compile-time信息。但是,将类型名作为字符串提供是运行时信息,这意味着它会在您实际执行程序时进行评估。所以简短的回答是:不,这是不可能的。
    猜你喜欢
    • 1970-01-01
    • 2013-03-23
    • 2018-02-18
    • 1970-01-01
    • 2011-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多