我有几件物品'它共享相似的功能,因此我从定义公共功能的基类派生它们。
接下来,我还希望拥有这些项目的专用列表,因此我从抽象基础容器中派生出类似容器的类。
以下代码演示了我的问题。
项
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)。为什么呢?
非常感谢任何帮助, 丹尼尔
答案 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
}