C# 在构造函数中导入IEnumerable

C# 在构造函数中导入IEnumerable,c#,.net,mef,C#,.net,Mef,我正在浏览一些代码,试图学习MEF:我理解如何导入示例服务,但我发现一些东西看起来像是在构造函数中导入集合 IObservableCollection在哪里实例化和填充?导入自定义类时很容易理解,但导入集合时,项从何处填充 private readonly IObservableCollection<NetworkServiceType> _observableNetworkServiceTypes; [ImportingConstructor] public MyConstruc

我正在浏览一些代码,试图学习MEF:我理解如何导入示例服务,但我发现一些东西看起来像是在构造函数中导入集合

IObservableCollection在哪里实例化和填充?导入自定义类时很容易理解,但导入集合时,项从何处填充

private readonly IObservableCollection<NetworkServiceType> _observableNetworkServiceTypes;

[ImportingConstructor]
public MyConstructor (IObservableCollection<NetworkServiceType> 
    observableNetworkServiceTypes)    
{
   _observableNetworkServiceTypes = observableNetworkServiceTypes;
}
private readonly IObservableCollection\u observeenetworkservicetypes;
[导入构造函数]
公共MyConstructor(IObservableCollection
ObservableNet(工作服务类型)
{
_ObservableNet工作服务类型=ObservableNet工作服务类型;
}

我通过搜索

[Export(typeof(IObservableCollection<NetworkServiceType>))]
[导出(typeof(IObservableCollection))]

我看到问题已被编辑,但希望这个答案仍然有用

问题的第一部分我相信你能理解。
IObservableCollection
应由实例化该类的人实例化;也就是说,他们还负责将这些信息传递给构造函数。DI和其他可以/可能参与帮助解决此问题的事情,但在这种情况下,DI仍需负责

您了解类是如何实例化和传入的,但不了解集合中的项,它们在哪里实例化。这可能会有所不同,但因为这是一个集合,所以集合中应该已经有一个项目数组。然而;由于这也是通过参考,这些项目可能会在其他地方发生变化;这意味着它们可能会在实例化后填充,或者谁知道呢。。。甚至在列表枚举期间。假设它们已经被实例化以编写安全代码是不安全的,但是假设它们应该被实例化也是合乎逻辑的;换句话说,你需要考虑如果你想在你的构造函数中使用传入的引用或者复制它,这样你就有了自己对集合的引用。 并希望在编辑之前对原始问题有所帮助;我看到你在下面的评论中仍然代表着这一点。我想,
IEnumerableCollection
确实有一个
IEnumerable
的基础以及其他基础,但是
IEnumerableCollection
是一个独特的接口(不是我所知道的.NET),所以我不能肯定。(为了说明这一点,创建名为
IEnumerableCollection
的类型是多余的,因为集合应该已经可以枚举了……)总之,回到正题。您最初会说,“当导入IEnumerable时,我找不到填充项的来源。”我想与大家分享这一点,希望它能有所帮助。。。当某个对象被称为或引用为
Enumerable
IEnumerable
IEnumerable
时,它更像是引用一个函数或委托,调用时返回一个值。该函数或方法有一个占位符,当同一个调用者再次调用它时,它可以选择它停止的地方;基本上允许您在迭代中调用时从同一个函数返回多个项。一种方法是使用
yield
关键字,您将在示例中看到。返回值可以是已引用的对象,也可以是在调用时实例化的对象。还有更多的可枚举的,但现在我们就到此为止

这意味着,当您引用一个
可枚举的
类型时,您期望从枚举中得到的项目可能存在,也可能不存在。您总是简单地引用一个方法来获取项(以便更容易理解)。我在这里使用术语查询,虽然它在使用Linq和SQL时更为相关,但其思想是相同的。我们可以有一个对查询的引用,在调用它之前永远不会得到任何项

以这个小应用程序为例,希望它能帮助说明上面所有的jibber jabber。这是一个小的控制台应用程序,你可以复制和粘贴。在第10行(
foreach(items中的var item)
)上放置一个断点,在第18行(
yield return Activator.CreateInstance();
)上放置一个断点。请注意,即使第9行已经有了对items的引用,我们还是先到达了第10行断点。事实上,如果我们从未使用
foreach
(或者以任何方式迭代项)在这个应用程序中,我们将永远不会实例化新对象(意思是
Activator.CreateInstance();
永远不会被调用)。直到我们迭代项(我称之为查询项),我们才真正得到新对象。 注意:这并不是说问题中的实例化就是这样做的,因为我假设不是这样。我只是说明.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
}
使用系统;
使用System.Collections.Generic;
命名空间问题\答案\控制台\应用程序
{
班级计划
{
静态void Main(字符串[]参数)
{
//对IEnumerable的引用
//在循环中使用时,其行为非常类似于函数。
var items=GetItems();
//For each处理IEnumerable类型并在内部调用GetEnumerator()方法。
//GetEnumerator()返回IEnumerator,它有1个属性和2个方法::Current、MoveNext()和Reset()
//它基本上调用GetEnumerator(),然后调用MoveNext()和Current来给出结果
foreach(项目中的var项目)
控制台写入线(项目);
//下面是上面手动编写的循环示例,目的是帮助您将其可视化。
var枚举器=items.GetEnumerator();
while(枚举数.MoveNext())
Console.WriteLine(枚举器.Current);
//最后,我们不能编写语法,但这里有一个方法(如下所示)非常类似于foreach语法。
ForEach(items,item=>Console.WriteLine(item));
Console.Read();
}
静态空位ForEach(IEnumer