简体   繁体   中英

Strange, IEnumerable.ToList() creates entirely new objects

I know IEnumerable.ToList() is supposed to create a new List, but with the items pointing to the same original items in the IEnumerable, as discussed at ToList()-- Does it Create a New List?

However, I'm getting some strange behavior with my code using VS 2012; WPF; and .NET 4.0. It started when IEnumerable.SequenceEquals() seemed not to work as I expected. I dug around with my QuickWatch dialog, and, unbelievably, the following statement evaluates to false:

this.Items.First () == this.Items.ToList ()[ 0 ]

I even tried:

this.Items.ToList ().IndexOf(this.Items.First ())

which evaluated to -1.

Items is declared as a property on a WPF custom control, like so:

public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register (
        "Items", 
        typeof ( IEnumerable<UserLayoutType> ), 
        typeof ( UserLayoutSelectorControl ),
        new FrameworkPropertyMetadata ( null, FrameworkPropertyMetadataOptions.AffectsRender, UserLayoutSelectorControl.PropertyChanged ) );


public IEnumerable<UserLayoutType> Items
{
    get
    {
        return ( IEnumerable<UserLayoutType> ) this.GetValue ( UserLayoutSelectorControl.ItemsProperty );
    }
    set
    {    
        this.SetValue ( UserLayoutSelectorControl.ItemsProperty, value );                
    }
}

UserLayoutType is simply a class generated by the XSD tool, with the following declaration:

// 
// This source code was auto-generated by xsd, Version=4.0.30319.17929.
// 
namespace MyAssays.UserLayoutCore.UserLayoutUtility {
    using System.Xml.Serialization;


    /// <remarks/>
    [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.0.30319.17929")]
    [System.SerializableAttribute()]
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Xml.Serialization.XmlRootAttribute("UserLayout", Namespace="", IsNullable=false)]
    public partial class UserLayoutType {

This are the methods on a factory class that create the UserLayoutType Items in the first place:

public static IEnumerable<UserLayoutType> CreateFromFolder ( string folderPath )
    {
        if (String.IsNullOrEmpty(folderPath))
            throw new ArgumentNullException("folderPath", "Folder path must not be null");

        var userLayoutXmlFilePaths = Directory.GetFiles ( folderPath ).Where ( filePath => filePath.EndsWith ( ".UserLayout.xml", StringComparison.InvariantCultureIgnoreCase ) );
        return userLayoutXmlFilePaths.Select(filePath => UserLayoutFactory.CreateFromFile(filePath));
    }

    public static UserLayoutType CreateFromFile ( string filePath )
    {
        using ( var stream = new StreamReader ( filePath ) )
        {
            return ( UserLayoutType ) new XmlSerializer ( typeof ( UserLayoutType ) ).Deserialize ( stream );
        }
    }

Anybody have any idea what is happening? See image below: 在此输入图像描述

The main, probable, cause for why you're seeing new objects from this is that the IEnumerable<T> is wrapping a generator, and not a materialized collection.

Here's a simple LINQPad program to demonstrate:

void Main()
{
    IEnumerable<string> collection =
        from index in Enumerable.Range(1, 10)
        select "Index=" + index;

    var list1 = collection.ToList();
    var list2 = collection.ToList();

    ReferenceEquals(list1[0], list2[0]).Dump();
}

This will print False .

It will do this because the act of enumerating over the collection ( .ToList() in this case) will execute the deferred LINQ query, and since we're enumerating the collection twice, we execute it twice, producing different instances with the same values.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM