在方法内部创建List <t>会使其外部为空 - 为什么?</t>

时间:2014-03-30 15:27:08

标签: c# collections nullreferenceexception

我有一个C#类,它对传递给它的一个公共方法的XML进行了一些解析。我们的想法是,该方法从XML中提取信息,创建对象并在公共属性中设置它们的集合......

public class XmlParser {
  public List<Customer> Customers { get; set; }

  public void ProcessXml(string xml) {
    XElement data = XElement.Parse(xml);
    CreateEntities(Customers, data);
    // do other stuff...
  }
}

这样,我们可以在调用代码中做这样的事情......

XmlParser xp = new XmlParser();
xp.ProcessXml(xml);
// do something with xp.Customers

我正在尝试在解析器类中编写一个私有泛型方法,它将由ProcessXml()方法使用,并保存我一遍又一遍地编写样板代码。此方法的开头看起来像这样(为清晰起见,其他参数错过了)......

private void CreateEntities<T>(List<T> collection, XElement data)  {
  if (collection == null) {
    collection = new List<T>();
  }
  // process the XElement passed in, and add objects to the collection
}

我试图像这样使用它......

CreateEntities(Customers, data);

...其他参数允许编译器知道泛型类型,并允许该方法知道要创建的实体等。

但是,我遇到的问题是,虽然方法本身工作正常,并且正确填充了集合变量,但公共Customers属性仍然为null。

我认为传递引用类型,例如List&lt;&gt;一个方法允许方法修改类型,并在方法之外看到那些变化,比如this SO post中的递归答案(我知道这是一个字典,但我原以为这个原则会是一样的。)

我的方法如何将集合设置为新的List&lt;&gt;,但Customers(同一个对象)仍然为空?

更新:叹息,我应该学会阅读错误消息!

在我发布我的问题之前,我曾尝试通过ref传递集合,它给了我编译器错误。在继续计划B之前,我显然没有对这些消息给予足够的重视。

在阅读了这里的回复之后,我再次尝试了ref,并发现编译器错误是因为我试图通过ref传递公共属性,这是不允许的。我将属性从一个自动更改为一个带有支持字段,通过ref传递了支持字段,一切正常!

2 个答案:

答案 0 :(得分:3)

  

我认为传递引用类型,例如List&lt;&gt;方法允许方法修改类型,并在方法

之外看到这些更改

您对通过引用传递参数(使用ref修饰符)以及按值传递引用感到困惑。

当您将引用类型的值(例如List<Customer>)传递给某个方法时,默认情况下仍然按值传递该参数。您可以更改变量值引用的对象的内容,但是您无法更改所引用的原始参数的对象,这就是您要执行的操作。

想想这样......如果我把一张纸和家里的地址交给某人,那么他们可以做两件事:

  • 他们可以去我家,把我的前门漆成红色
  • 他们可以在我的地址上划掉并在纸上写下不同的地址

我将能够看到第一个动作的结果 - 它正在改变房子本身的一些东西。我不会能够看到第二个动作的结果,因为它只是改变纸上的内容......这只是什么的副本< em>我知道是我的家庭住址。

有关详细信息,请参阅my article on parameter passing in C#

要解决您的问题,我只需将您的CreateEntities方法更改为返回列表,而不是接受一个:

private List<T> CreateEntities<T>(XElement data)
{
    var list = new List<T>();
    // Populate the list...
    return list;
}

如果调用者想要将这些添加到现有列表中,他们可以轻松地这样做。

答案 1 :(得分:2)

我认为您使用 ref 错过了传递引用类型。有关详细信息ref (C# Reference)