代码之家  ›  专栏  ›  技术社区  ›  Daarwin

在构造函数中导入IEnumerable

  •  -1
  • Daarwin  · 技术社区  · 7 年前

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

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

    private readonly IObservableCollection<NetworkServiceType> _observableNetworkServiceTypes;
    
    [ImportingConstructor]
    public MyConstructor (IObservableCollection<NetworkServiceType> 
        observableNetworkServiceTypes)    
    {
       _observableNetworkServiceTypes = observableNetworkServiceTypes;
    }
    
    2 回复  |  直到 7 年前
        1
  •  1
  •   Michael Puckett II    7 年前

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

    问题的第一部分我相信你理解。这个 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
    }
    
        2
  •  0
  •   Daarwin    7 年前

    我通过寻找

    [Export(typeof(IObservableCollection<NetworkServiceType>))]
    
    推荐文章