当“T”类型的对象是IEnumerable时,我如何枚举它



这有点难以解释。所以它开始了。

我有一个这样的功能:

public T FooBar<T>(Func<T> function)
{
   T returnData = function();
   // want to iterate through returnData to do something to it
   return returnData;
}

如果returnData(T)是IEnumerable列表,那么我想通过returnData进行枚举,以使用反射来修改其内容。但我似乎做不到。当我试图将returnData强制转换为可枚举类型时,我得到了一个异常:

无法强制转换类型的对象

'System.Collections.Generic.List`1[Cars]'

键入

'System.Collections.Generic.List`1[System.Object]'.

我不知道返回类型会是一个"汽车"列表,例如提前,只在运行时。所以我必须使用反射来检查它是否是一个列表,然后尝试对其进行强制转换,以便我可以通过它进行枚举

除非我走错了路。如果它是T类型的,我如何通过returnData进行枚举?

一种方法是在T上添加类型约束,但这并不理想:

public T FooBar<T>(Func<T> function) where T : IEnumerable
{
    // T is not strongly typed for the enumerated item

如果你稍微改变了你的方法(w.r.t.T):

public IEnumerable<T> FooBar<T>(Func<IEnumerable<T>> function)

然后,您可以对正在枚举的实际项进行强键入,同时还可以接受可枚举对象。


所以我从你的问题的第二次阅读中注意到,对于T对变量returnData的含义有一些困惑。在FooBar()被传递List<Car>的情况下,TList<Car>,并且实际上与List<>本身的通用类型规范没有关联。你可以把它想象成某种List<U>,其中U是另一种未知类型。

在运行时,您将无法简单地访问U,因为它隐藏在T中。您可以按照其他一些回答者的建议使用重载,并提供一个非IEnumerable<U>方法和一个接受Func<IEnumerable<T>>类型参数的方法。

也许有了更多关于FooBar<T>目标的细节,我们可以提出一些更具体的建议。

if (returnData is System.Collections.IEnumerable)
{
   foreach (object o in (System.Collections.IEnumerable)returnData)
   {
      // Do something.
   }
}

不过,真的,为什么不增加一个这样的过载呢:

public T FooBar<T>(Func<IEnumerable<T>> function) 

您是否尝试过将类型转换为IEnumerable而不是IEnumerable<T>?使用IEnumerable,您仍然可以在foreach循环中使用它。每个项目将进入的变量应为object类型,即:

foreach(object item in (IEnumerable)T){...}

您应该首先检查以确保T实现了IEnumerable

这里的问题是IEnumerable和IEnumerableOf T不一样。。。但是您可以检查差异并在代码中说明。请注意,IEnumerableOfT继承了IEnumerable,因此您可以将通用版本的检查包装在非通用版本中。

以下内容在我写的一个小测试中对我有效——我希望它足以让你做你需要的事情。

这是肉和土豆:

class FooBarOfT
{
    public T FooBar<T>(Func<T> function)
    {
        T returnData = function();
        //Want to iterate through returnData to do something to it.
        if (returnData is IEnumerable) 
        {
            // get generic type argument
            var returnDataType = returnData.GetType();
            if (returnDataType.IsGenericType)
            {
                // this is a System.Collections.Generic.IEnumerable<T> -- get the generic type argument to loop through it
                Type genericArgument = returnDataType.GetGenericArguments()[0];
                var genericEnumerator =
                    typeof(System.Collections.Generic.IEnumerable<>)
                        .MakeGenericType(genericArgument)
                        .GetMethod("GetEnumerator")
                        .Invoke(returnData, null);
                IEnumerator enm = genericEnumerator as IEnumerator;
                while (enm.MoveNext())
                {
                    var item = enm.Current;
                    Console.WriteLine(string.Format("Type : {0}", item.GetType().Name));
                }
            }
            else
            {
                // this is an System.Collections.IEnumerable (not generic)
                foreach (var obj in (returnData as IEnumerable))
                {
                    // do something with your object
                }
            }
        }
        return returnData;
    }
}

我还建立了一些支持测试类:

class Foo
{
    private string _fooText;
    public Foo(string fooText)
    {
        _fooText = fooText;
    }
    public string Execute()
    {
        return string.Format("executed! with {0} !", _fooText);
    }
}
class Bar
{
    public string BarContent { get; set; }
}

还有一个小型控制台应用程序来运行一些测试:

class Program
{
    static void Main(string[] args)
    {
        // tests
        Func<string> stringFunc = () => 
            "hello!";
        Func<List<Foo>> listFooFunc = () => 
            new List<Foo> 
            { 
                new Foo("Hello!"),
                new Foo("World!")
            };
        Func<IEnumerable> ienumerableFooFunc = () =>
            new Hashtable
            {
                { "ItemOne", "Foo" },
                { "ItemTwo", "Bar" }
            };

        var fooBarOfT = new FooBarOfT();
        fooBarOfT.FooBar(stringFunc);
        fooBarOfT.FooBar(listFooFunc);
        fooBarOfT.FooBar(ienumerableFooFunc);
        Console.ReadKey();
    }
}

相关内容

  • 没有找到相关文章

最新更新