C
C#•5mo ago
UltraWelfare

Primary constructor parameter is null after being run in a Task

The following snippet of code is responsible for starting a background service
public class PeriodicCallingIdentificationService(CallService callService)
{
private Task? _executeTask;
private CancellationTokenSource? _stoppingCts;
private Modem? _modem;

public void StartExecuting(CancellationToken cancellationToken)
{
if (_modem is null) throw new InvalidOperationException("Can't start executing without modem");
_stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
_executeTask = Task.Run(async () =>
{
await DoWork(_stoppingCts.Token); // <-- here
_modem.Close();
_modem = null;
}, cancellationToken);
}
public class PeriodicCallingIdentificationService(CallService callService)
{
private Task? _executeTask;
private CancellationTokenSource? _stoppingCts;
private Modem? _modem;

public void StartExecuting(CancellationToken cancellationToken)
{
if (_modem is null) throw new InvalidOperationException("Can't start executing without modem");
_stoppingCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
_executeTask = Task.Run(async () =>
{
await DoWork(_stoppingCts.Token); // <-- here
_modem.Close();
_modem = null;
}, cancellationToken);
}
This service is being registered with Microsoft DI as a singleton. When the StartExecuting function is called, the callService is correctly being passed. However if I set a breakpoint inside the lambda of Task.Run, callService is null there... Any ideas?
6 Replies
UltraWelfare
UltraWelfare•5mo ago
Small Update: it isn't null, the debugger is messing something up :/ Also in before you tell me about BackgroundServices: I'm in blazor hybrid where these type of stuff dont work.
i like chatgpt
i like chatgpt•5mo ago
There will be no a backing field for callService if it is not used in your class. Where is it used?
public class Student(string name) // name will have no a backing field because this parameter is not used in the class.
{
public int Id { get; set; }
}
public class Student(string name) // name will have no a backing field because this parameter is not used in the class.
{
public int Id { get; set; }
}
is translated to
public class Student
{
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int <Id>k__BackingField;

public int Id
{
[CompilerGenerated]
get
{
return <Id>k__BackingField;
}
[CompilerGenerated]
set
{
<Id>k__BackingField = value;
}
}

[NullableContext(1)]
public Student(string name)
{
}
}
public class Student
{
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int <Id>k__BackingField;

public int Id
{
[CompilerGenerated]
get
{
return <Id>k__BackingField;
}
[CompilerGenerated]
set
{
<Id>k__BackingField = value;
}
}

[NullableContext(1)]
public Student(string name)
{
}
}
Complete case:
public class Student(string name)
{
public int Id { get; set; }
public string Name => name; // generate a shared backing field for name
public void Print() => Console.WriteLine(name); // generate a shared backing field for name


public string Hahaha { get; set; } = name; // does NOT generate a shared backing field for name
public string hihihi = name; // does NOT generate a shared backing field for name
}
public class Student(string name)
{
public int Id { get; set; }
public string Name => name; // generate a shared backing field for name
public void Print() => Console.WriteLine(name); // generate a shared backing field for name


public string Hahaha { get; set; } = name; // does NOT generate a shared backing field for name
public string hihihi = name; // does NOT generate a shared backing field for name
}
UltraWelfare
UltraWelfare•5mo ago
It's used inside DoWork It works as intended, it's just the debugger is showing weird information about the variables You can take a look at this small snippet:
internal class Program
{
static void Main(string[] args)
{
var printService = new PrintService();
var testService = new TestService(printService);

testService.StartExecuting();
Thread.Sleep(5000);
testService.StopExecuting();
Console.WriteLine("Done");
}
}

class PrintService
{
public void PrintSomething()
{
Console.WriteLine("Something");
}
}

class TestService(PrintService printService)
{

private CancellationTokenSource _cts;
private Task _task;

public void StartExecuting(CancellationToken cancellationToken = default)
{
_cts = new();
_task = Task.Run(async () =>
{
await DoWork(_cts.Token);
}, cancellationToken);
}

public void StopExecuting(CancellationToken cancellationToken = default)
{
_cts.Cancel();
_task.Wait(cancellationToken);
}

public async Task DoWork(CancellationToken cancellationToken)
{
while (true)
{
try
{
Console.WriteLine("Doing work");
printService.PrintSomething();

await Task.Delay(1000, cancellationToken);
} catch (OperationCanceledException)
{
Console.WriteLine("Operation cancelled");
break;
}
}
}
}
internal class Program
{
static void Main(string[] args)
{
var printService = new PrintService();
var testService = new TestService(printService);

testService.StartExecuting();
Thread.Sleep(5000);
testService.StopExecuting();
Console.WriteLine("Done");
}
}

class PrintService
{
public void PrintSomething()
{
Console.WriteLine("Something");
}
}

class TestService(PrintService printService)
{

private CancellationTokenSource _cts;
private Task _task;

public void StartExecuting(CancellationToken cancellationToken = default)
{
_cts = new();
_task = Task.Run(async () =>
{
await DoWork(_cts.Token);
}, cancellationToken);
}

public void StopExecuting(CancellationToken cancellationToken = default)
{
_cts.Cancel();
_task.Wait(cancellationToken);
}

public async Task DoWork(CancellationToken cancellationToken)
{
while (true)
{
try
{
Console.WriteLine("Doing work");
printService.PrintSomething();

await Task.Delay(1000, cancellationToken);
} catch (OperationCanceledException)
{
Console.WriteLine("Operation cancelled");
break;
}
}
}
}
It's a recreation of the debugger bug If you debug inside the lambda or DoWork the printService would be shown as null (although it isn't)
i like chatgpt
i like chatgpt•5mo ago
The generated state machines are confusing. 🙂
UltraWelfare
UltraWelfare•5mo ago
What do you mean
i like chatgpt
i like chatgpt•5mo ago
I attempted to understand the flow but the generated state machines by sharplab.io are confusing.
Want results from more Discord servers?
Add your server
More Posts