在我使用的大多数返回某种集合的方法中,我返回 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)
您正在修改参数 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)
如果您对引用类型的假设为真,则输出将是“假”然后是“真”