我看到这个问题已经被编辑过了,但希望这个答案仍然有用。
问题的第一部分我相信你理解。这个
IObservableCollection<NetowrkServiceType>
应该由实例化该类的人实例化;这意味着它们也负责将此准备传递给构造函数。DI和其他可以/可能涉及到的事情来帮助解决这个问题,但在这种情况下DI仍然要负责。
您了解类是如何实例化和传入的,但是集合中的项,它们在哪里实例化。嗯,这可能会有所不同,但因为这是一个集合,所以集合中应该已经有一个项目数组。但是,由于这也是通过引用实现的,所以这些项可能会在其他地方更改;这意味着它们可能会在实例化之后填充,或者谁知道呢。。。甚至在列举清单的时候。它是
假设它们已经实例化是不安全的
写安全代码但是
假设应该是这样也是合乎逻辑的
;换句话说,您需要考虑是使用传入的引用还是在构造函数中复制它,以便拥有自己的集合引用。
希望能在编辑之前帮助解决最初的问题;我看到你仍然在下面的评论中表示。我猜是的
IEnumerableCollection<NetworkServiceType>
有一个基本的
IEnumerable<T>
和其他人一样但是
IEnumerableCollection<T>
是一个独特的接口(不是我所知道的.NET),所以我不能肯定。(为了说明这一点;制作一个名为
IEnumerableCollection
是多余的,因为集合应该已经是可枚举的……)无论如何,回到正题。您最初会说,“导入IEnumerable时,我找不到从何处填充项。”我想与大家分享这一点,希望它能有所帮助。。。当某物被称为
Enumerable
,
IEnumerable
,或
IEnumerable<T>
然后更像是引用一个函数或委托,调用时返回一个值。函数或方法有一个占位符,当同一个调用者再次调用它时,它可以从它停止的地方开始;基本上允许您在迭代中调用时从同一个函数返回多个项。一种方法是使用
yield
您将在示例中看到的关键字。返回值可以是已经引用的对象,也可以在调用时实例化。
还有很多事要做
可枚举的
但现在让我们就这样吧。
这意味着当您引用
可枚举的
键入您期望从枚举中得到的项可能存在,也可能不存在。您总是简单地引用一个方法来获取项目(使其更容易理解)。我在这里使用查询这个术语,虽然它在使用Linq和SQL时更为相关,但其思想是相同的。我们可以引用一个查询,并且在调用它之前永远不会得到任何项。
以这个小应用程序为例,希望它能帮助说明上面所有的jibber-jabber。这是一个小的控制台应用程序,你可以复制和粘贴。在第10行放置断点(
foreach (var item in items)
)一个在18号线(
yield return Activator.CreateInstance<T>();
. 请注意,我们在到达第18行之前到达了第10行的断点,尽管我们已经在第9行中有了对项目的引用。事实上如果我们从不使用
foreach
(或者以任何方式迭代项目)在这个应用程序中,我们将永远不会实例化新对象(意味着
Activator.CreateInstance<T>();
直到我们迭代项目(我称之为查询),我们才真正得到新对象。
注意:这并不是说这就是你在问题中实例化所做的,因为我假设它不是。我只是想说明
可枚举的
类型由.NET查看。
using System;
using System.Collections.Generic;
namespace Question_Answer_Console_App
{
class Program
{
static void Main(string[] args)
{
// A reference to IEnumerable<T>
// Behaves much like a function when used in a loop.
var items = GetItems<object>();
// For each works on IEnumerable types and internally calls the GetEnumerator() method.
// GetEnumerator() returns IEnumerator<T> which has 1 property and 2 methods :: Current, MoveNext(), and Reset()
// It basically calls GetEnumerator() and then MoveNext() and Current to give us the results
foreach (var item in items)
Console.WriteLine(item);
//Here's an example of the loop above written manually just to help you visualize it.
var enumerator = items.GetEnumerator();
while (enumerator.MoveNext())
Console.WriteLine(enumerator.Current);
//Finally; we can't write syntax but here's a method (seen below) that's much like the foreach syntax.
ForEach(items, item => Console.WriteLine(item));
Console.Read();
}
static void ForEach<T>(IEnumerable<T> items, Action<T> action)
{
IEnumerator<T> enumerator = items.GetEnumerator();
iterateItems();
void iterateItems()
{
// Notice that it's not actually until we get HERE calling MoveNext() that the yield return Activator.CreateInstance<T>() is actually called in our application.
// And even now we don't have a reference to it ourselves; it's just placed into the Current property of the IEnumerator<T> type.
var hasAnotherItem = enumerator.MoveNext();
if (hasAnotherItem)
{
// HERE is where we finally gain our own reference to the instantiated object for this example.
T currentItem = enumerator.Current;
action.Invoke(currentItem);
iterateItems();
}
}
}
static IEnumerable<T> GetItems<T>()
{
yield return Activator.CreateInstance<T>();
}
}
// Outputs:
// System.Object
// System.Object
// System.Object
}