引用的数据在复制后会重置为其默认值

本文关键字:默认值 数据 复制 引用 | 更新日期: 2023-09-27 18:20:24

我遇到一个问题,数据似乎被重置为默认值。类如下(objectID是一个简单的枚举):

public class Output_args: EventArgs {
    public objectIDs outputtype;
    public int internalID;
    public int verdict;
    public int outputID;
    public long entrytime;
    public Output_args Copy() {
        Output_args args = new Output_args();
        args.entrytime = this.entrytime;
        args.internalID = this.internalID;
        args.outputID = this.outputID;
        args.outputtype = this.outputtype;
        args.verdict = this.verdict;
        return args;
    }
}

下面的代码创建对象。它在一个特定的线程中运行,比如Thread1。

class Class1 {
EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.AutoReset);
public event EventHandler<Output_args> newOutput;
public void readInput(){
    List<Output_args> newoutputlist = new List<Output_args>();
    /* 
    * code to determine the outputs
    */
    Output_args args = new Output_args();
    args.outputtype = objectIDs.stepID;
    args.internalID = step[s].ID;
    args.verdict = verdict;
    args.entrytime = System.DateTime.Now.Ticks;
    newoutputlist.Add(args.Copy());
    if (newOutput != null && newoutputlist.Count > 0) {
    // several outputs are being sent sequentially but for simplicity i've removed the for-loop and decision tree
        try {
            newOutput(null, newoutputlist[0].Copy());
        } catch (Exception) { }
    }
}
}

此事件的1个订阅者具有以下代码。处理器方法在camerafeed的线程上运行。newOutput事件处理程序正在Thread1上运行。

class Class2: Form {
    private Output_args lastoutput = new Output_args();
    public void newOutput(object sender, Output_args args) {
        lock (lastoutput) {
            lastoutput = args.Copy();
        }
    }
    public void processor(){
        lock (lastoutput) {
            if (lastoutput.entrytime + 10000000 > System.DateTime.Now.Ticks) {
            // do something
             }
        }
    }
}

当调用Class2的事件处理程序"newOutput"时,调试器会显示副本按预期工作,并为"entrytime"提供预期的刻度数
但是,当处理器方法想要读取"entrytime"时,其值为0。所有其他字段也指定了默认值
我试着用long类型的简单字段替换对象"lastoutput",并删除了锁,但结果是一样的:它在"newOutput"中得到了正确的赋值,但在processor方法中有其默认值(0)。

你知道为什么会这样吗?

引用的数据在复制后会重置为其默认值

您不应该锁定对象lastoutput,而应该锁定另一个对象,因为您重新分配了字段。

处理器启动并锁定用默认值初始化的默认字段实例new Output_args()

class Class2: Form {
    private object mylock = new object();
    private Output_args lastoutput;
    public void newOutput(object sender, Output_args args) {
        lock (mylock) {
            lastoutput = args.Copy();
        }
    }
    public void processor(){
        lock (mylock) {
            if (lastoutput == null) {
               //nothing to consume yet
            }
            else if (lastoutput.entrytime + 10000000 > System.DateTime.Now.Ticks) {
               // do something
            }
        }
    }
}

但如果消费者比生产者慢,则丢弃lastuput。如果需要,可以使用队列(或其他集合)作为缓冲区。

class Class2 {
    private Queue<Output_args> outputs = new Queue<Output_args>();
    public void newOutput(object sender, Output_args args) {
        lock (outputs) {
            outputs.Enqueue(args.Copy());
        }
    }
    public void processor(){
        lock (outputs) {
            if (outputs.Count > 0) {
                var lastoutput = outputs.Dequeue();
                if (lastoutput.entrytime + 10000000 > System.DateTime.Now.Ticks) {
                // do something
                }
            }
        }
    }
}

演示:https://dotnetfiddle.net/daHVD1