我是 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
安德烈
答案 0 :(得分:4)
IEnumerable<MaliciousSmall> MaliciousCode
:MaliciousCode
是MaliciousSmall
个对象的可迭代集合?那么这意味着它代表了一个集合,并提供了一些迭代它的方法吗?
排序 - IEnumerable<T>
提供了一种方法 - GetEnumerator
- 返回IEnumerator<T>
。 THAT 界面允许您迭代集合。 Pre-Linq所有IEnumerable
允许你做的是在foreach
循环中使用该集合(或直接使用提供的IEnumerator
,这很少见)。 Linq之后定义了IEumerable<T>
上的扩展方法,允许更复杂的查询,例如Select
,Where
,Count
等。
如果前面的断言为真,那么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;
}