从基类列表返回引用返回“什么都没有”。

时间:2015-09-08 19:26:39

标签: c# abstract-class derived-class

我有几件物品'它共享相似的功能,因此我从定义公共功能的基类派生它们。

接下来,我还希望拥有这些项目的专用列表,因此我从抽象基础容器中派生出类似容器的类。

以下代码演示了我的问题。

public abstract class QAbstractItem 
{
    public int xAbstractMember;
    public QAbstractItem(int a)
    {
        xAbstractMember = a;
    }
}

public class QSingleItem : QAbstractItem
{
    public int xSingleMember;
    public QSingleItem(int s, int a) : base(a)
    {
        xSingleMember = s;
    }
}

解释

public abstract class QAbstractItemsList 
{
    public List<QAbstractItem> xItems = new List<QAbstractItem>();

    protected void add(QAbstractItem xItem)
    {
        xItems.Add(xItem);
    }

    public void getFirst(QAbstractItem yItem)
    {
        yItem = xItems[0];        // XXX
    }
}

public class QSingleItemsList : QAbstractItemsList
{
    public void add(QSingleItem S) 
    {
        base.add(S);
    }
}

用法

 QSingleItemsList xSingleList = new QSingleItemsList();
 xSingleList.add(new QSingleItem(5, 5));

 QSingleItem xFirst = new QSingleItem(0,0);
 xSingleList.getFirst(xFirst);

最后一行代码应该(因为我需要)在xFirst中包含(5,5)。但是,它包含(0,0)。当调试器在线XXX时,xItems [0]和yFirst都是(5,5)。当代码返回到调用者(main)时,xFirst突然变为(0,0)。为什么呢?

非常感谢任何帮助, 丹尼尔

3 个答案:

答案 0 :(得分:3)

getFirst的实施不正确。您需要为其添加ref或out关键字。 ref关键字表示传入的值可以重新分配,out关键字表示忽略输入值,结果将在那里分配。

public void getFirst(ref QAbstractItem yItem)

public void getFirst(out QAbstractItem yItem)

然后就会像这样调用

QAbstractItem xFirst = new QSingleItem(0,0);
xSingleList.getFirst(ref xFirst);

让它发挥作用,但实际上它应该更接近

public QAbstractItem getFirst()

答案 1 :(得分:2)

public void getFirst(QAbstractItem yItem)
{
    yItem = xItems[0];        // XXX
}

yItem参数按值传递(即使它是引用类型;引用按值传递)。因此,当您为yItem指定值时,调用者不会受到影响,因为yItem仅包含原始引用的副本。为此,您需要通过引用传递yItem

public void getFirst(ref QAbstractItem yItem)
{
    yItem = xItems[0];        // XXX
}

但是,在这种情况下,您无法使用QSingleItem类型的参数调用它。

解决问题的另一种方法是使列表类具有通用性:

public class QItemsList<TItem> where TItem : QAbstractItem
{
    public List<TItem> xItems = new List<TItem>();

    protected void add(TItem xItem)
    {
        xItems.Add(xItem);
    }

    public void getFirst(out TItem yItem)
    {
        yItem = xItems[0];        // XXX
    }
}

如果您需要特定类型项目的专用方法,可以将它们添加到继承通用列表的类中:

public class QSingleItemsList : QItemsList<QSingleItem>
{
    // specialized methods here
}

答案 2 :(得分:0)

问题在于该方法:

public void getFirst(QAbstractItem yItem)
{
    yItem = xItems[0];        // XXX
}

您必须注意,当您将参数传递给方法时,会创建对yItem的引用的副本。因此,如果为yItem分配新值,则它对传递给方法getFirst的实际参数没有影响。 根据C#规范,它是正确的行为。

您可以考虑更改方法以返回第一个元素:

public QAbstractItem getFirst()
{
    return xItems[0];        // XXX
}