关于C#中IEnumerable接口的一些说明?

时间:2014-03-12 17:06:34

标签: c# .net

我是 C#(我来自Java)的新手,我怀疑使用:

我有这堂课:

namespace DataModel.MaliciousCode
{

    public class PagedMalicious : Shared.Paged
    {
        public IEnumerable<MaliciousSmall> MaliciousCode { get; set; }

    }
}

正如您所看到的,此类仅包含IEnumerable<MaliciousSmall> MaliciousCode

在我看来,阅读在线文档可以理解IEnumerable是一个接口,它为非泛型集合提供迭代器。

前一个断言究竟意味着什么?

我有 MaliciousSmall ,这是我的应用程序中的模型对象的类型(一个包含映射数据库中表的字段的属性的对象)

所以我怀疑是:

  • IEnumerable<MaliciousSmall> MaliciousCode:MaliciousCode是 MaliciousSmall 对象的可迭代集合?那么这意味着它代表了一个集合,并提供了一些迭代它的方法吗?

  • 如果前一个断言为真,那么 MaliciousCode 对象是一个可迭代的集合,但 IEnumerable 是一个接口,所以谁实现了迭代这个集合的方法(来自Java我认为没有提供实现方法的接口)

有人可以帮助我理解这些事情吗?

TNX

安德烈

4 个答案:

答案 0 :(得分:4)

  

IEnumerable<MaliciousSmall> MaliciousCodeMaliciousCodeMaliciousSmall个对象的可迭代集合?那么这意味着它代表了一个集合,并提供了一些迭代它的方法吗?

排序 - IEnumerable<T>提供了一种方法 - GetEnumerator - 返回IEnumerator<T> THAT 界面允许您迭代集合。 Pre-Linq所有IEnumerable允许你做的是在foreach循环中使用该集合(或直接使用提供的IEnumerator,这很少见)。 Linq之后定义了IEumerable<T>上的扩展方法,允许更复杂的查询,例如SelectWhereCount等。

  

如果前面的断言为真,那么ok MaliciousCode对象是一个可迭代的集合,但IEnumerable是一个接口,所以谁实现了迭代这个集合的方法(来自Java我认为接口是未提供已实施的方法)

通常,通过使用基础集合类型(如List<MaliciousSmall>MaliciousSmall[])来提供实现。因此IEnumerable实现由该类提供。 C#2.0中引入的yield关键字允许您返回&#34;一个IEnumerable<T>并让编译器提供实际的实现。

因此,在您的课程中,您可能在内部将该集合实现为List<T>

public class PagedMalicious : Shared.Paged
{
    public IEnumerable<MaliciousSmall> MaliciousCode { get; set; }

    public PagedMalicious()
    {
        MaliciousCode = new List<MaliciousSmall>();
    }

    // other private methods that add to MaliciousCode
}

IEnumerable<T>的使用允许您在不更改公共接口的情况下更改内部实现。

答案 1 :(得分:1)

您的属性MaliciousCode表示实现IEnumerable<T>接口的类的对象。就它而言,IEnumerable并不意味着什么。它只是提供了一种结构。用户有责任以任何方式实现接口提供的方法。

编辑:这是一个简单的示例:

private void Form3_Load(object sender, EventArgs e)
    {
        Parent parent = new Parent();
        parent.Child = new List<Child>(); // -> this is where implementer is decided.  
        //Before this line, Child property is not instantiated and is not referring to any object.
    }

    public class Parent
    {
        public IEnumerable<Child> Child { get; set; }
    }

    public class Child
    {
        public int MyProperty { get; set; }
    } 

答案 2 :(得分:0)

对你的怀疑: 是的,是的 界面本身无法实现任何内容,但您可以分配MaliciousSmall数组或List&lt; MaliciousSmall&gt;。它们都实现了IEnumerable&lt; MaliciousSmall&gt;

答案 3 :(得分:0)

IEnumerable<T>相当于Java的Iterable<T>。由于C#的早期版本没有泛型,IEnumerable是当时唯一可用的迭代器。您可以将其视为一种IEnumerable<object>

大多数通用集合类型实现IEnumerable<T>,包括数组。通用变体需要实现非泛型变体,因此大多数集合(通用或非通用)实现IEnumerable

但是,这些迭代器不仅限于表示集合。它们提供了允许您枚举项目的方法,这些方法也可以通过算法生成项目。例如 - 理论上 - 可以通过枚举提供无穷无尽的方数枚举,而无需将这些数字存储在任何地方。

在您的情况下,IEnumerable<MaliciousSmall> MaliciousCode属性可以逐个从DB中生成MaliciousSmall个对象,因为枚举是枚举而不首先将它们存储在集合对象中。

自己实施IEnumerable<T>需要实施IEnumerator<T> GetEnumerator()方法。它返回一个枚举器对象,该对象需要实现方法bool MoveNext()void Dispose()void Reset()和属性T Current { get; }

您可以通过编写大量代码来实现这些接口,也可以使用C#的迭代器。迭代器使用大量编译器魔法在幕后自动创建枚举和枚举器。请参阅:Iterators (C# and Visual Basic)


作为C#迭代器的一个例子,让我们用它们实现你的例子(我放弃了这里的setter):

public class PagedMalicious : Shared.Paged
{
    public IEnumerable<MaliciousSmall> MaliciousCode
    {
        get
        {
            using (var conn = new SqlConnection("<my server connection>")) {
                var cmd = new SqlCommand("SELECT name, number FROM myTable", conn);
                conn.Open();
                using (var reader = cmd.ExecuteReader()) {
                    while (reader.Read()) {
                        var maliciousSmall = new MaliciousSmall {
                            Name = reader.GetString(0), 
                            Number = reader.GetInt32(1) 
                        };
                        yield return maliciousSmall;
                    }
                }
            }
        }
    }
}

每次执行yield return时,控件都会传回给调用者并获取下一个项目。 getter方法的状态保持不变,并且此处的执行将暂停,直到调用者继续迭代并需要下一个项目。当他这样做时,执行将在yield return语句之后重新开始。

您可以从此示例中看到,枚举是以惰性方式计算的。以下代码总结了整个表的编号。这些项目永远不会存储在集合中;它们从数据库中检索并在枚举时创建。如果您有一百万条记录,这是一个优势! (您将在高效的代码段中使用SQL SUM聚合函数,所以。)

var pagedMalicious = new PagedMalicious();
int sum = 0;
foreach (MaliciousSmall item in pagedMalicious.MaliciousCode) {
    sum += item.Number;
}