Creating an array of objects using initializers seems to fail - c#

I have a GameObject we'll call the GM. Attached to it is a script that's meant to be the primary logical controller for a game.
In that script, somewhere, I have:
private dbEquipment equipment_database = new dbEquipment();
The relevant snippet from dbEquipment.cs:
public class dbEquipment {
private int total_items = 13;
private clEquipment[] _master_equipment_list;
public dbEquipment() {
_master_equipment_list = new clEquipment[total_items];
_master_equipment_list[0] = new clEquipment {
... //large amount of object initializing here
};
... //etc, for all 13 items
}
}
When I run Unity, I get:
NullReferenceException: Object reference not set to an instance of an object
Pointed at the line:
_master_equipment_list[0] = new clEquipment { ...
I tried running through the array and initializing every clEquipment object to an empty clEquipment() first:
for(int x = 0; x < total_items; x++) { _master_equipment_list[x] = new clEquipment(); }
just to be totally sure that the array was actually filled, but I got the same result.
I've also tried changing it to be a List<clEquipment>, and changing everything appropriately -- no dice.
Any ideas?

My guess is that you may been including a null reference in the section that says //large amount of object initializing here when you create a new clEquipment.
_master_equipment_list[0] = new clEquipment {
... //check for nulls here
};

You might want to post the code for the clEquipment class. You say you tried initializing every object...did you do that before the break line? If it didn't break, thats a good sign.
Also, hard to tell from your code, but do you need a "()" in the initialization where it breaks? Just a thought
_master_equipment_list[0] = new clEquipment () {

Related

Local variable not initializing in C#

I have a static function that initializes a list of tiles:
private static bool MyFunction(SomeObj obj)
{
List<Tile> tiles = obj.Tile.GetTilesBetween(otherTile);
// do stuff
}
Later in MyFunction(), I initialize a collection using LINQ:
{
// we did stuff
List<Commands> commands = CommandsOccuringInTimespan(obj.timeElapsed);
IEnumerable<Commands> match = commands.Where(c => tiles.Contains(c.End));
// do more stuff
}
However, the presence of these lines, specifically the initialization of match, is causing tiles to either not initialize or to initialize but not be available in the Debugger. I can't understand why this would be happening.
I can seem to make it work if I make a copy of tiles and use that when initializing match:
// we did stuff
List<Commands> commands = CommandsOccuringInTimespan(obj.timeElapsed);
List<Tile> copyOfTiles = new List<Tile>(tiles);
IEnumerable<Commands> match = commands.Where(c => copyOfTiles.Contains(c.End));
// do more stuff
}
C# 7 (I think; this is a Unity3D app so I believe that's the current supported version).
Try adding the .ToList() method to tiles:
List<Tile> tiles = obj.Tile.GetTilesBetween(otherTile).ToList();

How to evaluate local variable/ parameter state with Roslyn

I have a bit of complicated situation. I must create analyzers/ code fix providers for situations such as a parameter is only assigned but never used or local variable are never used.
For the parameter situation, I'm going for the method declaration and looking at the parameter list to get all the analyzer. I'm going through assignment expressions within the method and I filter the parameters that were assigned with an helper method.
Where it gets fuzzy is I have no clue or to know when a local variable/parameter is used or not. I've gone through symbols but they can't tell me that variable used/ not used. I could try to find how many times a variable's name was mentioned inside a method by turning the method declaration syntax context in a string and look for the parameters that were assigned but that's simply such a BAD idea.
I'm really stuck and I would some help for this from anyone who had previous experience with this kind of situation.
For people who might ask, I'm mostly looking for the missing logic for the analyzer. I have no idea how the code fix provider will work. If you have an idea of what I could do, feel free to include it in your answer ! As of now, I was thinking that a local variable that's not used could be deleted from a method and the same could go for an unused parameter. I'm not sure at the moment.
UPDATE
I'm now trying to use the DataFlow API but it's not working for me at the moment. The oldest answer of this thread gave me a starting point but it's actually not working.
I came up with my own way :
private static bool IsLocalVariableBeingUsed(VariableDeclaratorSyntax variableDeclarator, SyntaxNodeAnalysisContext syntaxNode)
{
var model = syntaxNode.SemanticModel.Compilation.GetSemanticModel(variableDeclarator.SyntaxTree);
var methodBody = variableDeclarator.AncestorsAndSelf(false).OfType<MethodDeclarationSyntax>().First();
var lastMethodNode = methodBody?.ChildNodes().LastOrDefault();
if (lastMethodNode == null)
return false;
var readWrite = syntaxNode.SemanticModel.AnalyzeDataFlow(variableDeclarator, lastMethodNode);
}
But this also is not working. When using a test with NUnit :
var input = #"
class TestClass {
void TestMethod ()
{
int i;
}
}";
I get the following message when the runtime gets to either readWrite or result(from oldest answer):
System.ArgumentOutRangeException Index was out of range Must be non negative and lesser than the size of the collection"
But before that in my analyzer, when I try to validate my node to make sure it's not null and create the appropriate elements for the data flow API, there's no code break (not sure if that is the appropriate term) but at the moment I cannot progress.
You can see whether or not most variable are used (read/written) via the DataFlowAnalysis APIs. I've written an introduction to this API on my blog.
I believe in your case, you're looking for variables that are never read.
var tree = CSharpSyntaxTree.ParseText(#"
public class Sample
{
public void Foo()
{
int unused = 0;
int used = 1;
System.Console.Write(used);
}
}");
var Mscorlib = PortableExecutableReference.CreateFromAssembly(typeof(object).Assembly);
var compilation = CSharpCompilation.Create("MyCompilation",
syntaxTrees: new[] { tree }, references: new[] { Mscorlib });
var model = compilation.GetSemanticModel(tree);
var methodBody = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single().Body;
DataFlowAnalysis result = model.AnalyzeDataFlow(methodBody);
var variablesDeclared = result.VariablesDeclared;
var variablesRead = result.ReadInside.Union(result.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
foreach(var variable in unused)
{
Console.WriteLine(variable);
}
Building on JoshVarty's answer, to get this to work in a diagnostic, I would register a SyntaxNodeAction for all MethodDeclaration Syntax Kinds and then look inside the body for unused variables:
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeIt, SyntaxKind.MethodDeclaration);
}
private static void AnalyzeIt(SyntaxNodeAnalysisContext context)
{
var method = context.Node as MethodDeclarationSyntax;
var dataFlow = context.SemanticModel.AnalyzeDataFlow(method.Body);
var variablesDeclared = dataFlow.VariablesDeclared;
var variablesRead = dataFlow.ReadInside.Union(dataFlow.ReadOutside);
var unused = variablesDeclared.Except(variablesRead);
if (unused.Any())
{
foreach (var unusedVar in unused)
{
context.ReportDiagnostic(Diagnostic.Create(Rule, unusedVar.Locations.First()));
}
}
}

How can I add an object to a collection without knowing it's type?

I added a "console" in my game, in which I can type commands, and receive a response (it's based on this). I need to be able to access objects that I instantiate in my Game.cs in my console class. I can't pass them to the constructor, since I don't know how much there will be once the "engine" is done.
I tried using a method to add the objects to a Dictionnary<string, object> but I can't access the properties.
What I'd like to be able to do:
Game1.cs
TileMap tileMap = new TileMap();
BakuConsole console;
...
console = new BakuConsole(this, Content.Load<SpriteFont>("ConsoleFont"));
console.AddRef("tileMap", tileMap);
BakuConsole.cs
public void AddRef(/* some args */) {
// halp!
}
public void Execute(string input) {
switch (input)
{
case "some --command":
console.WriteLine(g.ToString());
// execute stuff, with an object that was added via AddRef()
console.WriteLine("");
console.Prompt(prompt, Execute);
break;
default:
console.WriteLine("> " + input + " is not a valid command.");
console.WriteLine("");
console.Prompt(prompt, Execute);
break;
}
}
I hope I am clear enough. Thanks!
Edit:
I just don't want my constructor to grow too big in case I add more types:
TileMap tileMap = new TileMap();
OtherType1 ot1 = new OtherType1();
OtherType2 ot2 = new OtherType2();
OtherType3 ot3 = new OtherType3();
OtherType4 ot4 = new OtherType4();
OtherType5 ot5 = new OtherType5();
IronPython does exactly what I want to do, and does it via Globals.Add("string", object"). However, I can't seem to find it in the source (of IronPython).
From what you described, you don't actually need a dictionary, you need several properties on some object, probably directly on BakuConsole;
class BakuConsole
{
… // your current code here
public TileMap TileMap { get; set; }
public OtherType1 OtherType1 { get; set; }
…
}
Then, you can set it like this:
console.TileMap = tileMap;
console.OtherType1 = otherType1;
…
And then when you use it, you won't have any problems with accessing properties.
I can see that you are passing a reference of Game to the Console class. Why don't you use that reference to access what you need from the Game class?
You neeed to specify the class name in dictionary of which object you are going to add in dictionary.
Suppose, I had to add "Game1" objects,then we should initialize dictionary in following way...
Dictionary<string, Game1> dicDemo = new Dictionary<string, Game1>();
Game1 objgame1 = new Game1();
dicDemo.Add(string.Empty,objgame1);

Reference type not passed as reference

I have this strange problem in my unit tests. See the following code
_pos = null;
Utilities.InitPOS(_pos, trans);
Assert.IsNotNull(_pos); //fails
The InitPOS functions looks like
public static void InitPOS(POSImplementation pos, Transaction newTransaction)
{
pos = new POSImplementation();
pos.SomeProp = new SomeProp();
pos.SomeProp.SetTransaction(newTransaction);
Assert.IsNotNull(pos);
Assert.IsNotNull(pos.SomeProp);
}
The object POSImplementation is an implementation of some interface and it is a class, so it is a reference type...
Any idea?
You're passing a reference to an object to InitPOS (namely a null reference), not a reference to the variable named _pos. The effect is that the new POSImplementation instance is assigned to the local variable pos in the InitPOS method, but the _pos variable remains unchanged.
Change your code to
_pos = Utilities.InitPOS(trans);
Assert.IsNotNull(_pos);
where
public static POSImplementation InitPOS(Transaction newTransaction)
{
POSImplementation pos = new POSImplementation();
// ...
return pos;
}
pos = new POSImplementation();
Just what are you doing there, if someone is passing pos into the method already? Are you missing a ref attribute on that parameter maybe?
You don't pass the instance by reference,
you pass the reference by value.

GC collecting...what?

I am trying to optimize my engine (C# + SlimDX) to make as less allocations as possible (to prevent the GC from firing too often) using as guide a profiler that gives me where the garbaged object are generated. Its going pretty well (going down from like 20 MB garbaged every 5s to 8 MB garbaged every 1 minute and half (yep, it was very little optimized XD))
There is a method where I can't find anything declarated and i don't know what's to do. It seems this method generate 2 garbaged object per execution in its body (not on a called function) :
Can somebody guide me to understand why this function generate object to be garbaged? I really don't have a clue.
public override void Update()
{
base.Update();
if (LastCheckInstancesNumber != Instances.Count)
{
LastCheckInstancesNumber = Instances.Count;
_needToRegenerateUpdate = true;
}
// Crea byte array da usare nel prossimo draw.
if (_needToRegenerateUpdate)
{
Int32 PrimitivesCount = Instances.Count;
Int32 Size = PrimitivesCount * 80;
if ((ByteUpdateTemp != null) && (ByteUpdateTemp.Length < Size))
ByteUpdateTemp = new byte[Size];
int offset = 0;
PrimitivesCount = 0;
Int32 Count = Instances.Count;
for (int i = 0; i < Count; i++)
{
InstancedBase3DObjectInstanceValues ib = Instances[i];
if (ib.Process)
{
MathHelper.CopyMatrix(ref ib._matrix, ref MatrixTemp);
MathHelper.CopyVector(ref ib._diffuseColor, ref ColorTemp);
ObjectUpdateTemp[0] = MatrixTemp.M11;
ObjectUpdateTemp[1] = MatrixTemp.M12;
ObjectUpdateTemp[2] = MatrixTemp.M13;
ObjectUpdateTemp[3] = MatrixTemp.M14;
ObjectUpdateTemp[4] = MatrixTemp.M21;
ObjectUpdateTemp[5] = MatrixTemp.M22;
ObjectUpdateTemp[6] = MatrixTemp.M23;
ObjectUpdateTemp[7] = MatrixTemp.M24;
ObjectUpdateTemp[8] = MatrixTemp.M31;
ObjectUpdateTemp[9] = MatrixTemp.M32;
ObjectUpdateTemp[10] = MatrixTemp.M33;
ObjectUpdateTemp[11] = MatrixTemp.M34;
ObjectUpdateTemp[12] = MatrixTemp.M41;
ObjectUpdateTemp[13] = MatrixTemp.M42;
ObjectUpdateTemp[14] = MatrixTemp.M43;
ObjectUpdateTemp[15] = MatrixTemp.M44;
ObjectUpdateTemp[16] = ColorTemp.X;
ObjectUpdateTemp[17] = ColorTemp.Y;
ObjectUpdateTemp[18] = ColorTemp.Z;
ObjectUpdateTemp[19] = ColorTemp.W;
ByteConverter.WriteSingleArrayToByte(ref ObjectUpdateTemp, ref ByteUpdateTemp, offset);
offset += 20;
PrimitivesCount++;
}
}
SynchronizedObject so = SynchronizationEventWriter.LockData();
so.Synchronizedobject = ByteUpdateTemp;
SynchronizationEventWriter.Update();
SynchronizationEventWriter.UnlockData();
_needToRegenerateUpdate = false;
so = SynchronizationEventWriterNum.LockData();
so.Synchronizedobject = PrimitivesCount;
SynchronizationEventWriterNum.Update();
SynchronizationEventWriterNum.UnlockData();
}
}
Notes :
The new byte[Size] is NEVER called due to caching.
The MathHelper function simply copy each element (Single) from one object to another without creating anything.
The base.Update() does almost nothing (and anyway is derived from ALL object in my engine, but only here i have the garbage object)
Thanks!!!
EDIT:
internal void GetLock()
{
Monitor.Enter(InternalLock);
Value.Locked = true;
Value.LockOwner = Thread.CurrentThread;
}
public SynchronizedObject LockData()
{
Parent.GetLock();
return Parent.Value;
}
Here's the code of the LockData(). I don't think it generates anything :|
I've resolved!!!
The problem was that the so.Synchronizedobject = PrimitivesCount; was assigning an Int32 to an Object class. It seems that this replaces every time the object causing the old object to be garbaged.
I resolved by using a box class to enclose the Int32 object and simply change the value inside.
What's in base.Update(), anything?
Can your profiler dump the heap? If so why I'd put a breakpoint just before this method and dump the heap and then again straight afterwards. That way you'll be able to see what type of object has been created.
Short of that a brute force approach of commenting out line by line is another (horrible) idea.
Do your MathHelper methods create a temp object?
I'm just guessing, but it looks like you're creating two SynchronizedObject objects in the bottom nine lines of that function:
SynchronizedObject so = SynchronizationEventWriter.LockData();
and
so = SynchronizationEventWriterNum.LockData();
No detailed knowledge of SynchronizedObject or whether LockData() actually creates anything, but it's the only choice I can see in your code...

Categories

Resources