通过扩展方法向 IEnumerable 添加项目不起作用?

Joh*_*ney 3 c# ienumerable

在我使用的大多数返回某种集合的方法中,我返回 IEnumerable 而不是特定类型(例如 List)。在许多情况下,我有另一个集合要与结果 IEnumerable 结合,这与使用 AddRange 方法获取一个 List 并添加另一个 List 完全一样。我有以下示例,在其中我创建了一个扩展方法,该方法应该将项目集合添加到基本集合中,同时调试这似乎有效,但在原始集合中从未添加项目。我不明白这一点,为什么不添加它们,是否存在我缺少的 IEnumerable 实现方面的内容?我知道 IEnumerable 是一个只读接口,但我没有在下面的示例中添加到此列表中,我正在替换它,

class Program
{
    static void Main(string[] args)
    {
        var collectionOne = new CollectionContainerOne();
        var collectionTwo = new CollectionContainerTwo();

        // Starts at 1- 50 //
        collectionOne.Orders.AddRange(collectionTwo.Orders);
        // Should now be 100 items but remains original 50 //
    }
}

public class CollectionContainerOne
{
    public IEnumerable<Order> Orders { get; set; }

    public CollectionContainerOne()
    {
        var testIds = Enumerable.Range(1, 50);
        var orders = new List<Order>();
        foreach (int i in testIds)
        {
            orders.Add(new Order() { Id = i, Name = "Order #" + i.ToString() });
        }
        this.Orders = orders;
    }
}

public class CollectionContainerTwo
{
    public IEnumerable<Order> Orders { get; set; }

    public CollectionContainerTwo()
    {
        var testIds = Enumerable.Range(51, 50);
        var orders = new List<Order>();
        foreach (int i in testIds)
        {
            orders.Add(new Order() { Id = i, Name = "Order #" + i.ToString() });
        }
        this.Orders = orders;
    }
}

public class Order
{
    public int Id { get; set; }
    public string Name { get; set; }

    public override string ToString()
    {
        return this.Name;
    }
}

public static class IEnumerable
{
    public static void AddRange<T>(this IEnumerable<T> enumerationToAddTo, IEnumerable<T> itemsToAdd)
    {
        var addingToList = enumerationToAddTo.ToList();
        addingToList.AddRange(itemsToAdd);

        // Neither of the following works // 
        enumerationToAddTo.Concat(addingToList);
        // OR
        enumerationToAddTo = addingToList;
        // OR
        enumerationToAddTo = new List<T>(addingToList);
    }
}
Run Code Online (Sandbox Code Playgroud)

pho*_*oog 5

您正在修改参数 enumerationToAddTo,这是一个引用。但是,引用本身并不是通过引用传递的,因此当您修改引用时,在调用方中无法观察到更改。此外,不能ref在扩展方法中使用参数。

你最好使用Enumerable.Concat<T>. 或者,您可以使用具有 Add(T) 方法的 ICollection。不幸的是,List<T>.AddRange没有在任何接口中定义。

这里有一个例子来说明通过引用传递引用类型。正如 Nikola 指出的那样,这并不是真正有用的代码。不要在家里尝试这个!

void Caller()
{
    // think of ss as a piece of paper that tells you where to find the list.
    List<string> ss = new List<string> { "a", "b" };

    //passing by value: we take another piece of paper and copy the information on ss to that piece of paper; we pass that to the method
    DoNotReassign(ss);

    //as this point, ss refers to the same list, that now contains { "a", "b", "c" }

    //passing by reference: we pass the actual original piece of paper to the method.
    Reassign(ref ss);

    // now, ss refers to a different list, whose contents are { "x", "y", "z" }
}
void DoNotReassign(List<string> strings)
{
    strings.Add("c");
    strings = new List<string> { "x", "y", "z" }; // the caller will not see the change of reference

    //in the piece of paper analogy, we have erased the piece of paper and written the location
    //of the new list on it.  Because this piece of paper is a copy of SS, the caller doesn't see the change.
}
void Reassign(ref List<string> strings)
{
    strings.Add("d");
    //at this point, strings contains { "a", "b", "c", "d" }, but we're about to throw that away:

    strings = new List<string> { "x", "y", "z" };

    //because strings is a reference to the caller's variable ss, the caller sees the reassignment to a new collection
    //in the piece of paper analogy, when we erase the paper and put the new object's
    //location on it, the caller sees that, because we are operating on the same
    //piece of paper ("ss") as the caller 
}
Run Code Online (Sandbox Code Playgroud)

编辑

考虑这个程序片段:

string originalValue = "Hello, World!";
string workingCopy = originalValue;
workingCopy = workingCopy.Substring(0, workingCopy.Length - 1);
workingCopy = workingCopy + "?";
Console.WriteLine(originalValue.Equals("Hello, World!"); // writes "True"
Console.WriteLine(originalValue.Equals(workingCopy); // writes "False"
Run Code Online (Sandbox Code Playgroud)

如果您对引用类型的假设为真,则输出将是“假”然后是“真”