【问题标题】:Cast using Reflection in C#在 C# 中使用反射进行投射
【发布时间】:2011-03-01 00:08:03
【问题描述】:

我创建了一个如下的通用函数(只是一个证明),它将采用 List<T> 集合并将其反转,返回一个新的 List<T> 作为其输出。

public static List<T> ReverseList<T>(List<T> sourceList)
{
    T[] outputArray = new T[sourceList.Count];
    sourceList.CopyTo(outputArray);
    return outputArray.Reverse().ToList();
}

证明的目的是我只知道T在运行时是什么。因此,我使用反射来调用上述方法,如下所示:

List<int> myList = new List<int>() { 1, 2, 3, 4, 5 }; // As an example, but could be any type for T

MethodInfo myMethod = this.GetType().GetMethod("ReverseList");
MethodInfo resultMethod = myMethod.MakeGenericMethod(new Type[] { typeof(int) });
object result = resultMethod.Invoke(null, new object[] { myList });

这里有两个问题:

  1. 在第二行中,我想提供类似于myList.GetType().GetGenericArguments()[0].GetType() 的东西,而不是提供typeof(int),以使事情更灵活,因为直到运行时我才知道T。当 Invoke 按如下方式运行时,这样做会导致运行时错误:“'System.Collections.Generic.List'1[System.Int32]' 类型的对象无法转换为 'System.Collections.Generic.List'1[ System.RuntimeType]'。”
  2. Invoke() 方法的结果返回一个对象。调试时,我可以看到该对象是 List 类型,但尝试使用它告诉我我有一个无效的演员表。我假设我需要使用反射将结果装箱为正确的类型(即在本例中,相当于(result as List&lt;int&gt;)。

有没有人可以帮助我解决这个问题?抱歉,如果不清楚,如果被问到,我可能会提供更多详细信息。

TIA

【问题讨论】:

  • 等等...那你为什么不直接说myList.GetType().GetGenericArguments()[0].GetType()
  • 第二个框中的代码是打算放在泛型函数中,还是打算实际传递 Type 的实例?
  • 啊,因为这导致异常如下:"Object of type 'System.Collections.Generic.List1[System.Int32]' 不能转换为类型'System.Collections.Generic.List1[System.RuntimeType]'."
  • @siride no 第二个框中的代码使用反射调用泛型方法。第 3 行即将更正,因为@Ben Voigt 对此部分有答案。
  • @mnield 那么我看不出问题出在哪里。您已经知道列表的类型,即int。无需反射解决方案。

标签: c# .net reflection


【解决方案1】:

你的GetType() 太多了。发生在每个人身上。

myList.GetType().GetGenericArguments()[0]System.Type -- 您正在寻找的那个。

myList.GetType().GetGenericArguments()[0].GetType() 是一个描述System.TypeSystem.Type(嗯,实际上是具体的子类System.RuntimeType)。


另外,您的ReverseList 功能严重矫枉过正。为了避免调用List.Reverse,它做了一个额外的副本。有一个更好的方法来规避它:

public static List<T> ReverseList<T>(List<T> sourceList)
{
    return Enumerable.Reverse(sourceList).ToList();
}

public static List<T> ReverseList<T>(List<T> sourceList)
{
    var result = new List<T>(sourceList);
    result.Reverse();
    return result;
}

public static List<T> ReverseList<T>(List<T> sourceList)
{
    var result = new List<T>();
    result.Capacity = sourceList.Count;
    int i = sourceList.Count;
    while (i > 0)
        result.Add(sourceList[--i]);
    return result;
}

【讨论】:

  • 您先生,君子学者!这正是我在那里所做的。 +1 用于解决第一个问题。
  • 顺便说一句,是的,这种方法有点矫枉过正。这不是我真正关心的方法,而是调用它的方式和处理结果的方式。实际上,就这个演示而言,ReverseList&lt;T&gt; 可能刚刚返回了相同的列表。
【解决方案2】:

要以List&lt;T&gt; 的形式访问它,是的,您需要使用反射找到 T(可能在接口上,例如 typeof(IList&lt;&gt;),并使用更多反射和 MakeGenericMethod 等。老实说,它不是值得:你最好检查一下非泛型IList

var list = result as IList;
if (list != null)
{
    // loop over list etc
}

泛型广告反射不是好朋友。

请注意,在 4.0 中,您还可以使用 dynamic 和泛型在此处执行一些技巧。

【讨论】:

  • 好吧,也许我有点昏头了。我可以很好地找到 T 的类型,我遇到的麻烦是将它转换为可以将其分配给事物。 IE。 List&lt;int&gt; jeffTheVariable = result; 无法编译,因为我无法将 Object 隐式转换为 List。我很欣赏泛型和反射不太好,但是我的目标应用程序中的库有大量我真的需要自动化的类。
  • 根据我的经验,泛型和反射相处得很好,如果你有一些示例代码可以查看并认真关注细节。当然,你用它们做了一些非常棘手的事情,所以你应该比我更清楚,但我认为你可能会因为你所攻击的非常棘手的问题而产生偏见。
  • 有偏见,我......是的 - 可能 :) 让我感动的是,它真的很容易获得 90% 的路程,而最后 10% 总是让我摸不着头脑/拉扯我的脱发。
  • @Ben 其他方式 - 使用了很多,我认为 在很多情况下这种方法有点过头了;对于 95% 以上的此类情况,仅使用非泛型就可以正常工作,并且更容易正确处理。
【解决方案3】:

Invoke() 方法的结果 返回一个对象。调试时,我 可以看到对象的类型 列表,但尝试使用它告诉 我说我的演员阵容无效。我 假设我需要使用反射 将结果装箱到正确的位置 类型(即在本例中, 相当于(结果为列表)。

我能想到的唯一解决方法是传递一个空列表作为方法的第二个参数并填充该列表 - Invoke() 返回的引用将始终只有类型对象,但在泛型方法中,您确实可以访问类型本身:

List<int> reverseList = new List<int>();
resultMethod.Invoke(null, new object[] { myList, reverseList });

...

public static void ReverseList<T>(List<T> sourceList, List<T> resultList)
{
    T[] outputArray = new T[sourceList.Count];
    sourceList.CopyTo(outputArray);
    resultList.AddRange(outputArray.Reverse());
}

【讨论】:

  • 这是一种非常简单的方法。我认为这可能是一个“只见树木不见森林”的时刻。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-25
  • 1970-01-01
  • 2011-07-13
  • 2013-05-05
相关资源
最近更新 更多