unity IEnumerable的几种用法

Where It Can Be Used

  1. Iterating Over Collections: You can use IEnumerable or IEnumerable<T> to iterate over collections like arrays, lists, dictionaries, etc. The foreach loop in C# works with IEnumerable, allowing you to easily loop through any collection implementing this interface.

  2. Lazy Evaluation: When used with the yield keyword, IEnumerable allows for deferred execution, meaning the collection is only computed as it's being iterated. This can be beneficial for performance, especially with large datasets.

  3. Custom Iteration: If you're creating a custom collection, implementing IEnumerable allows you to define how the collection should be iterated. You can control the enumeration logic inside the GetEnumerator() method.

  4. LINQ Queries: Language Integrated Query (LINQ) methods work with collections that implement IEnumerable<T>. This enables you to perform SQL-like queries on collections in a type-safe manner.

  5. Abstraction and Encapsulation: By exposing a collection as IEnumerable, you're restricting access to modification methods like Add, Remove, etc., encapsulating the details and providing a more controlled way to access the data.

  6. Interoperability: Using IEnumerable as a return type or parameter type makes your methods more flexible and able to work with various kinds of collections. Since most collection classes in .NET implement IEnumerable, this ensures a broad compatibility.

  7. 对集合进行迭代:您可以使用IEnumerable或IEnumerable<T>来对数组、列表、字典等集合进行迭代。在C#中,foreach循环与IEnumerable一起工作,使您可以轻松遍历实现了该接口的任何集合。

    惰性求值:当与yield关键字一起使用时,IEnumerable允许延迟执行,意味着集合只在迭代时计算。这在性能方面可能是有益的,尤其是在处理大型数据集时。

    自定义迭代:如果您正在创建自定义集合,实现IEnumerable允许您定义如何迭代该集合。您可以在GetEnumerator()方法中控制枚举逻辑。

    LINQ查询:语言集成查询(LINQ)方法适用于实现IEnumerable<T>的集合。这使您能够以类型安全的方式对集合执行类似SQL的查询。

    抽象和封装:通过将集合暴露为IEnumerable,您限制了对添加、删除等修改方法的访问,封装了细节,并提供了更受控制的访问数据的方式。

    互操作性:将IEnumerable用作返回类型或参数类型使您的方法更加灵活,能够与各种类型的集合一起工作。由于.NET中的大多数集合类都实现了IEnumerable,这确保了广泛的兼容性。

public IEnumerable<int> GetEvenNumbers(int[] numbers)
{
    foreach (int number in numbers)
    {
        if (number % 2 == 0)
            yield return number;
    }
}

In this example, the method returns an IEnumerable<int> that consists of even numbers from the input array. Using yield return provides lazy evaluation, computing each value only when requested.

In summary, IEnumerable and IEnumerable<T> are powerful interfaces in .NET used for iterating over collections, enabling lazy evaluation, encapsulating collection details, facilitating LINQ queries, and more.

Example 1: Filtering a List of Objects

public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

public IEnumerable<Product> GetProductsAbovePrice(IEnumerable<Product> products, decimal minPrice)
{
    foreach (var product in products)
    {
        if (product.Price > minPrice)
            yield return product;
    }
}

Example 2: Implementing Custom Iterator for a Collection

public class FibonacciSequence : IEnumerable<int>
{
    private int _count;

    public FibonacciSequence(int count)
    {
        _count = count;
    }

    public IEnumerator<int> GetEnumerator()
    {
        int a = 0, b = 1;

        for (int i = 0; i < _count; i++)
        {
            yield return b;
            (a, b) = (b, a + b);
        }
    }

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

Example 3: Combining Multiple Lists into a Single Sequence

public IEnumerable<string> CombineNames(IEnumerable<string> firstNames, IEnumerable<string> lastNames)
{
    using (var firstNameEnumerator = firstNames.GetEnumerator())
    using (var lastNameEnumerator = lastNames.GetEnumerator())
    {
        while (firstNameEnumerator.MoveNext() && lastNameEnumerator.MoveNext())
        {
            yield return firstNameEnumerator.Current + " " + lastNameEnumerator.Current;
        }
    }
}

Example 4: Using LINQ to Query Objects

public IEnumerable<string> GetNamesOfExpensiveProducts(IEnumerable<Product> products)
{
    return products.Where(p => p.Price > 100).Select(p => p.Name);
}

Example 5: Reversing a Collection

public IEnumerable<T> Reverse<T>(IEnumerable<T> collection)
{
    Stack<T> stack = new Stack<T>(collection);

    while (stack.Count > 0)
    {
        yield return stack.Pop();
    }
}

Example 6: Generic Print Method for Different Collections

Suppose you want to create a method that prints the elements of any collection. Since most collection classes in .NET implement IEnumerable, you can use this interface as a parameter type to create a method that works with arrays, lists, sets, queues, stacks, etc. 

public void PrintElements(IEnumerable collection)
{
    foreach (var item in collection)
    {
        Console.WriteLine(item);
    }
}

You can now call this method with different collection types:

int[] array = { 1, 2, 3 };
List<string> list = new List<string> { "A", "B", "C" };
HashSet<double> set = new HashSet<double> { 1.1, 2.2, 3.3 };

PrintElements(array); // Prints integers
PrintElements(list); // Prints strings
PrintElements(set); // Prints doubles

Why this Demonstrates Interoperability
  • Versatility: The PrintElements method accepts any collection that implements IEnumerable. It doesn't matter whether it's an array, list, set, or some other collection type. As long as the collection implements IEnumerable, the method can handle it.

  • Maintainability: By depending on the abstraction (IEnumerable) rather than a concrete class, the method is more resilient to changes. If a new collection type is introduced in the future, the method can handle it without modification, as long as the new collection type implements IEnumerable.

  • Encapsulation: The method only needs to know that the collection can be iterated, and it doesn't need to know any other details about the collection's implementation. This encapsulates the details of the collection and promotes separation of concerns.

In summary, this example illustrates how IEnumerable can be leveraged to create methods that work with a wide variety of collection types. This promotes interoperability, maintainability, and robustness in the design of systems that work with collections.

Example extra: Traversing a Tree Structure

public class TreeNode
{
    public int Value { get; set; }
    public List<TreeNode> Children { get; set; } = new List<TreeNode>();
}

public class Tree
{
    public TreeNode Root { get; set; }

    public IEnumerable<TreeNode> Traverse(TreeNode node)
    {
        if (node == null)
            yield break;

        yield return node; // Return the current node

        // Recursively traverse child nodes
        foreach (var child in node.Children)
        {
            foreach (var descendant in Traverse(child))
            {
                yield return descendant;
            }
        }
    }
}

In this example, the Traverse method takes a TreeNode and returns an IEnumerable<TreeNode> that includes the node itself and all its descendants in the tree. The method uses recursive calls to Traverse to yield each descendant node in a depth-first manner.

You could then use this method to iterate over all nodes in the tree, starting from the root:

Tree tree = CreateTree(); // Assume this method creates the tree
foreach (var node in tree.Traverse(tree.Root))
{
    Console.WriteLine(node.Value);
}

This example demonstrates how IEnumerable can be used to facilitate recursive algorithms, in this case providing an elegant way to traverse a tree structure. By leveraging the deferred execution provided by the yield keyword, this approach avoids building intermediate collections and offers efficient memory usage, particularly for large trees.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值