I have a System.Threading.Timer
that receives some data each second, and I want its callback to put the received data into an object. I tried to implement that using C#'s reference types mechanism. Here's the current callback:
private void Receive(object? obj) {
var data = GetData();
obj = (object)data; // Does nothing
}
And here's the method that starts the timer (timer
is a field):
public void Start(Image image) {
timer = new Timer(
Receive,
image,
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1)
);
}
Expected behavior: each second the data (which is image data) is received and put to the image, the reference to which is specified in parameter image
.
Actual behavior: when I defined a variable of type Image
, passed it to the Start
method and checked its value (using the Visual Studio debugger) after 5 seconds, it was the empty Bitmap
I assigned to it at the very start.
I have also checked that the data (containing non-empty image) is sent properly.
Can anybody tell me what's the issue, or, alternatively, suggest a different way to change the "state" object in a timer callback?
CodePudding user response:
obj = (object)data;
only sets the data locally in the Receive
method. You could fix it by creating a wrapper object
public class ImageData
{
public Image Image { get; set; }
}
Then create a static instance of it that can be accessed from where you need it
public static readonly ImageData Data = new ImageData();
Depending on where you must access the images it can also an instance member and be private; however, it must always be the same instance that you used to start the timer.
Then start like this
public void Start() {
timer = new Timer(
Receive,
Data,
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1)
);
}
And receive
private void Receive(object? obj) {
var data = (ImageData)obj;
data.Image = GetData();
}
Now, you can access the new images through the static Data.Image
property.
CodePudding user response:
In the Recieve method you get an obj as input reference. Then you try to set a value to obj. This last step cannot work, since you work on the reference. The only way it could work is, if the input reference is given as a ref, which is
private void Receive(ref object? obj) {}
Passing a reference type by reference enables the called method to replace the object to which the reference parameter refers in the caller.