C
C#2y ago
faint

System.NullReferenceException in an if statement

I keep getting System.NullReferenceException directing me to the last if statement in the following code:
public override IEnumerable<Node> GetReachableNodes(TransformComponent xform, EntityQuery<NodeContainerComponent> nodeQuery, EntityQuery<TransformComponent> xformQuery,
MapGridComponent? grid, IEntityManager entMan)
{
if (grid == null)
yield break;

entMan.System<SpreaderSystem>().GetNeighbors(xform.Owner, Name, out _, out _, out var neighbors);

foreach (var neighbor in neighbors)
{
if (!nodeQuery.TryGetComponent(neighbor, out var nodeContainer) ||
!_nodeContainer.TryGetNode<SpreaderNode>(nodeContainer, Name, out var neighborNode))
{
continue;
}

yield return neighborNode;
}
}
public override IEnumerable<Node> GetReachableNodes(TransformComponent xform, EntityQuery<NodeContainerComponent> nodeQuery, EntityQuery<TransformComponent> xformQuery,
MapGridComponent? grid, IEntityManager entMan)
{
if (grid == null)
yield break;

entMan.System<SpreaderSystem>().GetNeighbors(xform.Owner, Name, out _, out _, out var neighbors);

foreach (var neighbor in neighbors)
{
if (!nodeQuery.TryGetComponent(neighbor, out var nodeContainer) ||
!_nodeContainer.TryGetNode<SpreaderNode>(nodeContainer, Name, out var neighborNode))
{
continue;
}

yield return neighborNode;
}
}
The problem is in _nodeContainer.TryGetNode.... After I moved TryGetNode from one place to another and added a new parameter, that error started appearing. Why does it always appear if all TryGetNode's parameters are nullable:
public bool TryGetNode<T>(NodeContainerComponent? component, string? identifier, [NotNullWhen(true)] out T? node) where T : Node
{
if (identifier == null || component == null)
{
node = null;
return false;
}

if (component.Nodes.TryGetValue(identifier, out var n) && n is T t)
{
node = t;
return true;
}

node = null;
return false;
}
public bool TryGetNode<T>(NodeContainerComponent? component, string? identifier, [NotNullWhen(true)] out T? node) where T : Node
{
if (identifier == null || component == null)
{
node = null;
return false;
}

if (component.Nodes.TryGetValue(identifier, out var n) && n is T t)
{
node = t;
return true;
}

node = null;
return false;
}
26 Replies
mtreit
mtreit2y ago
_nodeContainer could be null?
faint
faintOP2y ago
Unsure what you mean, since nodeContainer is a method and it returns bool value
mtreit
mtreit2y ago
_nodeContainer is a variable Likely a field
faint
faintOP2y ago
oh, I see what you mean lemme explain
faint
faintOP2y ago
here is what it looks like in code
faint
faintOP2y ago
I'm not that good at C# to explain it better
mtreit
mtreit2y ago
So it's null The default value for all reference types is null
faint
faintOP2y ago
thonk why is it so
mtreit
mtreit2y ago
Because variables for reference types are essentially a pointer. Null means they aren't pointing to anything yet.
Angius
Angius2y ago
That ! is a hint, it tells the compiler "shut up about null, I know what I'm doing"
faint
faintOP2y ago
I just don't know why it doesn't work only with my system if that way of getting a system is used everywhere in the solution I might wanna do another way that also works
Angius
Angius2y ago
What is that [Dependency] attribute? Is it some field-based dependency injection framework at work?
mtreit
mtreit2y ago
Fixing this might be as simple as:
private readonly NodeContainerSystem _nodeContainer = new();
private readonly NodeContainerSystem _nodeContainer = new();
But yeah I have no idea what that Dependency attribute is
faint
faintOP2y ago
I shift+clicked it and here is the code
using System;

namespace Robust.Shared.IoC
{
/// <summary>
/// Specifies that the field this is applied to is a dependency,
/// which will be resolved by <see cref="IoCManager" /> when the containing class is instantiated.
/// </summary>
/// <remarks>
/// <para>
/// The dependency is resolved as if <see cref="IoCManager.Resolve{T}()" /> were to be called,
/// but it avoids circular references and init order issues due to internal code in the <see cref="IoCManager" />.
/// </para>
/// <para>
/// The dependency can be injected into read only fields without issues,
/// and as a matter of fact it is recommended to use read only fields.
/// </para>
/// <para>
/// If you would like to run code after the dependencies have been injected, use <see cref="IPostInjectInit" />
/// </para>
/// </remarks>
[AttributeUsage(AttributeTargets.Field)]
public sealed class DependencyAttribute : Attribute
{
}
}
using System;

namespace Robust.Shared.IoC
{
/// <summary>
/// Specifies that the field this is applied to is a dependency,
/// which will be resolved by <see cref="IoCManager" /> when the containing class is instantiated.
/// </summary>
/// <remarks>
/// <para>
/// The dependency is resolved as if <see cref="IoCManager.Resolve{T}()" /> were to be called,
/// but it avoids circular references and init order issues due to internal code in the <see cref="IoCManager" />.
/// </para>
/// <para>
/// The dependency can be injected into read only fields without issues,
/// and as a matter of fact it is recommended to use read only fields.
/// </para>
/// <para>
/// If you would like to run code after the dependencies have been injected, use <see cref="IPostInjectInit" />
/// </para>
/// </remarks>
[AttributeUsage(AttributeTargets.Field)]
public sealed class DependencyAttribute : Attribute
{
}
}
Angius
Angius2y ago
Yeah, it does seem to be some weird DI framework
faint
faintOP2y ago
It’s RobustToolbox a game engine for SS14
Angius
Angius2y ago
In that case, is the class you're injecting the dependency into registered in the IoC container?
faint
faintOP2y ago
can’t answer since I don’t know much about IoC and stuff sorry
Angius
Angius2y ago
Time to hit the docs, then And see how IoC works in this toolbox thing
faint
faintOP2y ago
yeah, was going to visit a IoC docs page after I finish the thing Im working currently on lol
mtreit
mtreit2y ago
You could try not using dependency injection just to get it working
faint
faintOP2y ago
Currently trying another thing of getting a system for my class the main reason I asked it here is cause the error didn’t seem clear to me like uh I didn’t get what exactly is null also I just think that Dependency thing doesn’t work in classes that inherit Node. Cause I can surely say it works fine for _EntitySystem_s it finally works! Appreciate your help @mtreit @ZZZZZZZZZZZZZZZZZZZZZZZZZ
Angius
Angius2y ago
Nice
faint
faintOP2y ago
Just had to use so called entitymanager to get the system though now I’m really curious how IoC works thanks once again!
Angius
Angius2y ago
IoC/DI generally works by creating instances of what you think you'll need at some point, storing them in a container, and then injecting those instances where they're needed Basically, there's only one place where the things get created, so it's easy to swap them later if need be For example, instead of having to swap every var uploader = new ImgurUploader() for var uploader = new CatboxUploader(), you only swap services.AddSingleton<IUploader, ImgurUploader>() for services.AddSingleton<IUploader, CatboxUploader>() in one place And everything that requests an IUploader as a dependency will now get the new one
faint
faintOP2y ago
heartowo
Want results from more Discord servers?
Add your server