我有一段不起作用的代码,我很感激你们可以提供给我的任何帮助
下面的代码正在生成一个异常...但我认为它不应该,除非我误解了ref语义。
编辑:感谢所有答案...我知道我在One.Produce方法中实现了一个新的Queue对象...但这是我真正想做的,我想Main._queue来持有对One._queue的引用。 这有可能吗?using System;
using System.Collections.Generic;
namespace ConsoleApplication2
{
class One
{
Queue<string> _queue;
public One(ref Queue<string> queue)
{
// should be assigning by reference
_queue = queue;
}
public void Produce()
{
_queue = new Queue<string>();
_queue.Enqueue("one");
}
}
class Program
{
static void Main(string[] args)
{
Queue<string> _queue = new Queue<string>();
One one = new One(ref _queue);
one.Produce();
// this generates an exception, since _queue is empty
// i'd have thought _queue would have one item, "one"
string value = _queue.Dequeue();
}
}
}
答案 0 :(得分:3)
问题是在函数Produce
中,您正在实例化一个新的Queue
并将其分配给私有成员One._queue
;这会覆盖您在构造函数中对One._queue
所做的赋值。但是,本地_queue
引用了您从未加入的其他Queue<string>
。
您可以通过移除Produce
的第一行来解决此问题,以获取以下内容:
public void Produce() {
_queue.Enqueue("one");
}
顺便说一下,您不需要通过引用将_queue
传递给构造函数来实现您想要实现的目标。也就是说,以下内容也可以使用
public One(Queue<string> queue) {
_queue = queue;
}
当您希望main中的本地_queue
在Queue<string>
构造函数执行后引用One
的不同实例时,将使用按引用传递。
答案 1 :(得分:1)
尝试以下方法:
public One(Queue<string> queue)
{
// should be assigning by reference
_queue = queue;
}
public void Produce()
{
_queue.Enqueue("one");
}
答案 2 :(得分:1)
在Produce()
方法中,删除以下行:
_queue = new Queue<string>();
你正在创建一个新的队列实例。
答案 3 :(得分:0)
one.Produce()用新的“空”队列()替换_queue。 这就是为什么字符串值= _queue.Dequeue()抛出错误(b / c _queue)
答案 4 :(得分:0)
从Produce
方法中删除此行:
_queue = new Queue<string>();
这会消除您通过引用传入的现有Queue<String>
的引用,并引用新的Queue<String>
。
答案 5 :(得分:0)
问题是ref
关键字只会影响它声明的方法。因此,您可以在Main
的构造函数中更改One
的队列,但不能在Produce
方法中更改。
在您的代码中,One
正在创建对同一队列对象的第二个引用。 Produce
方法只是更改了第二个引用。
换句话说,当您通过引用调用通过参数传递的方法时,被调用的方法将能够更改引用的对象,但仅限于此调用站点。调用返回后,_queue
方法中Main
变量引用的任何对象都将保留在那里。
另一个考虑因素。 One
的构造函数(您评论“应该通过引用分配”的位置)的工作方式与ref
关键字不存在时的工作方式完全相同在那里。只有当作业被转换为queue = _queue;
时,ref
关键字才会有所作为。
Holder<T>
类可能有意义的一个解决方案是创建一个Holder
类,如下所示:
public class Holder<T> {
public T { get; set; }
}
然后,One
类将对Holder<Queue<string>>
对象起作用。 Main
方法也必须适用于Holder<Queue<string>>
。这样,One
可以更改队列实例,它将反映在Main
。
好的,好的。我知道这个解决方案很尴尬,但对你的问题的要求对我来说也很尴尬。这是一个修辞问题吗?或者你想在这里解决一个更大的问题?如果是后者,我很想知道这个更大的问题是什么。
另一种解决方案是使用pointers。完全可以在C#中完成,但根本不推荐。如果您有兴趣,我可以尝试使用指针编写解决方案。
你自己的回答让我想到了第三种可能的解决方案。它本质上与其他两种解决方案非常相似。不要用英语解释,让我用C#来表示。
class One
{
Queue<string>[] queueArray;
public One(Queue<string>[] queueArray)
{
if (queueArray == null) throw new ArgumentNullException("queueArray");
if (queueArray.Length != 1) throw new ArgumentException("queueArray must have one and only one item");
this.queueArray = queueArray;
}
public void Produce()
{
queueArray[0] = new Queue<string>();
queueArray[0].Enqueue("one");
}
}
class Program
{
static void Main(string[] args)
{
var queueArray = new Queue<string>[] { new Queue<string>() };
One one = new One(queueArray);
one.Produce();
string value = queueArray[0].Dequeue(); //this line sets "one" to value
}
}
答案 6 :(得分:0)
为什么不简单地执行以下操作:
public void Produce()
{
_queue.Clear();
_queue.Enqueue("one");
}
答案 7 :(得分:-1)
解决此类问题的一般方法....使用调试器逐步执行代码,并查看引发异常的行。