This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 6 years ago.
I'm having problem with a school assignment in C#.
I include only a part of the code here, I hope that it suffices.
I'm creating an array of the Bottle class with index 25. The Bottle class contains three properties.
Now I need to get and set values in the array, but I don't manage to.
See my example below. Where am I doing wrong? The program doesn't show any errors but the compilation does not succeed. If any more code would be necessary I'm happy to give it!
public class Sodacrate
{
private Bottle[] bottles;
public Sodacrate() // Constructor for handling new sodas in the soda crate.
{
bottles = new Bottle[25];
bottles[0].Brand = "Fanta";
bottles[0].Price = 15;
bottles[0].Kind = "Soda";
}
}
public class Bottle
{
private string brand;
private double price;
private string kind;
public string Brand
{
get { return brand; }
set { brand = value; }
}
public double Price
{
get { return price; }
set { price = value; }
}
public string Kind
{
get { return kind; }
set { kind = value; }
}
}
There is no object at the zero index of the array. What you are doing is setting up memory for the array here:
bottles = new Bottle[25];
Then what you are doing is trying to set properties on the first object in that array here:
bottles[0].Brand = "Fanta";
bottles[0].Price = 15;
bottles[0].Kind = "Soda";
What is missing is the following:
bottles[0] = new Bottle();
So to summarize here is what you are doing:
//Give me a box big enough to hold 25 bottles
//Set the brand on the first bottle
This is what you should be doing:
//Give me a box big enough to hold 25 bottles
//Put the first bottle in the box
//Set the brand on the first bottle
Because Bottle is a reference type, so this statement will create an array contains 25 element with value is default value of reference type which is null.
bottles = new Bottle[25];
So, you must assign value to bottle[0] before use it. like this:
bottles[0] = new Bottle();
Related
This question already has answers here:
C# SortedSet<T> and equality
(4 answers)
Closed 2 years ago.
I am trying to play around with sorted sets in c# for a custom objects and for some reason, it seems like the sorted sets might not be using the references of the objects to store the data..
In the following code snippet, I use a custom IComparer to rely on the Counts property of the custom class. But for some reason, this seems to affect the add functionality. and the counter.Add(two) line does not make any addition to the set even though it is a different reference and has a different value for two properties.
Am I missing something? Have I got something wrong about how SortedSets are supposed to work in C#?
Code Snippet
public class SortedStructureTesting
{
public void TestingSortedSets()
{
SortedSet<CounterSetup> counter = new SortedSet<CounterSetup>(new CompareCounts());
CounterSetup one = new CounterSetup(1);
CounterSetup two = new CounterSetup(2);
CounterSetup three = new CounterSetup(3, 2);
counter.Add(one);
counter.Add(two); // Does not work. This value does not get added to the set.
counter.Add(three);
var max = counter.Max;
counter.Remove(max);
var sec = counter.Max;
counter.Remove(sec);
}
public class CounterSetup
{
public static Random random = new Random();
public CounterSetup(int no, int cnt = 1)
{
Number = no;
Count = cnt;
Blah = new string(Guid.NewGuid().ToString());
}
public int Number { get; private set; }
public int Count { get; set; }
public string Blah { get; private set; }
}
public class CompareCounts : IComparer<CounterSetup>
{
public int Compare(CounterSetup one, CounterSetup two)
{
return one.Count.CompareTo(two.Count);
}
}
}
Thanks for taking a look and helping!
Well [Sorted]Set can contain distinct items only; i.e. Set can't have two more equal items. You compare item (treat them as equal) with respect of Count: if two items have the same Count they are considered equal. In your code
CounterSetup one = new CounterSetup(1); // one.Count == 1
CounterSetup two = new CounterSetup(2); // two.Count == 1
CounterSetup three = new CounterSetup(3, 2); // three.Count == 2
you have one.Count == two.Count == 1 that's why one and two are equal for the counter sorted set. When you add items, the second (which is two) is ignored:
counter.Add(one);
counter.Add(two); // Ignored: there's already an item (one) with the same Count
counter.Add(three);
If you want separated criteria (one for Equals and the other is for order) you can try good old HashSet which you can represent as ordered with a help of Linq:
using System.Linq;
...
// Items in counter are unique (based on MyEqualityComparer)
HashSet<CounterSetup> counter = new HashSet<CounterSetup>(
new MyEqualityComparer()
);
// Now we order counter items by different criterium (here we sort by `Count`)
var ordered = counter
.OrderBy(item => item.Count);
I searched the heck out of it, and i can't solve it.
I have a program setup like this (it's in Unity and Visual Studio 2019 for C#):
Note that the CSV loading goes fine, when i debug the code i can see everything filled with corect data.
#region character class
public class _Character
{
public int Id { get; set; }
public int Variation { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
}
#endregion
//Tools.LoadCsv generates a string[,] from a csv file
//Tools.IntParse parses int's with a lot of format error checking
void Start()
{
#region load characters class
string[,] CharacterCSV = Tools.LoadCsv(#"Assets/GameDB/character.csv");
List<_Character> Character = new List<_Character>();
for (int i = 1; i < CharacterCSV.GetUpperBound(0); i++)
{
_Character temp = new _Character();
temp.Id = Tools.IntParse(CharacterCSV[i, 0]);
temp.Variation = Tools.IntParse(CharacterCSV[i, 1]);
temp.Name = CharacterCSV[i, 2];
temp.LastName = CharacterCSV[i, 3];
Character.Add(temp);
}
CharacterCSV = null;
#endregion
}
I barely understand objects, so i'm sorry if i am doing it wrong.
The questions i have are:
Why does the Object List generation Háve to be in Start ? I can't seem to do that in it's own class.
How can i get an object from the Character Object List, containing Id = 100 and Name = "John"
, and access it from another class or method.
I ussualy frankenstein the heck out of code and make it good enough for me, but now i wanted to make something nice and cant seem to get to the objects.
Thanks in advance!
//the major issue was declaring the object inside the class, when declared outside the class, the List Object was available to the outside world.
List<_Character> Character = new List<_Character>(); move to outside Start{}
I'm not editing the question to correct the code, because the question needs to stay clear.
//
Why does the Object List generation has to be in Start ? I can't seem to do that in it's own class.
How can i get an object from the Character Object List, containing Id = 100 and Name = "John" , and access it from another class or method.
If you want to retrieve a character from outside of the class, then, you have to declare the list outside of the Start function, otherwise, the list will be destroyed since it's a local variable of the function.
// Declare the list outside of the functions
private List<_Character> characters;
void Start()
{
// Avoid using regions, they encourage you to make very long functions with multiple responsabilities, which is not advised
// Instead, create short and simple functions, and call them
LoadCharactersFromCSV();
}
void LoadCharactersFromCSV()
{
string[,] CharacterCSV = Tools.LoadCsv(#"Assets/GameDB/character.csv");
// If you can, indicate the approximate numbers of elements
// It's not mandatory, but it improves a little bit the performances
characters = new List<_Character>( CharacterCSV.GetUpperBound(0) );
// I believe `i` should start at 0 instead of 1
for (int i = 1; i < CharacterCSV.GetUpperBound(0); i++)
{
// I advise you to create a constructor
// instead of accessing the properties one by one
_Character temp = new _Character();
temp.Id = Tools.IntParse(CharacterCSV[i, 0]);
temp.Variation = Tools.IntParse(CharacterCSV[i, 1]);
temp.Name = CharacterCSV[i, 2];
temp.LastName = CharacterCSV[i, 3];
characters.Add(temp);
}
CharacterCSV = null;
}
// Using this function, you will be able to get a character from its id
public _Character GetCharacter( int id )
{
for (int 0 = 1; i < characters.Count; i++)
{
if( characters[i].Id == id )
return characters[i];
}
// Return null if no character with the given ID has been found
return null ;
}
Then, to call GetCharacter from another class:
public class ExampleMonoBehaviour : MonoBehaviour
{
// Replace `TheClassName` by the name of the class above, containing the `Start` function
// Drag & drop in the inspector the gameObject holding the previous class
public TheClassName CharactersManager;
// I use `Start` for the sake of the example
private void Start()
{
// According to your code, `_Character` is defined **inside** the other class
// so you have to use this syntax
// You can get rid of `TheClassName.` if you declare `_Character` outside of it
TheClassName._Character john = CharactersManager.GetCharacter( 100 );
}
}
This question already has answers here:
Access private fields
(4 answers)
Closed 6 years ago.
I recently had an interview with C# questions. One of them I cannot find an answer to.
I was given a class, looks like this:
public class Stick
{
private int m_iLength;
public int Length
{
get
{
return m_iLength;
}
set
{
if (value > 0)
{
m_iLength = value;
}
}
}
}
Also, a main class was given
static void Main(string[] args)
{
Stick stick = new Stick();
}
The task was to add code to the main that will cause m_iLength in the Stick class to be negative (and it was stressed out that it can be done).
I seem to miss something. The data member is private, and as far as I know the get and set function are by value for type int, so I do not see how this can be done.
Reflection is always the most direct:
var type = typeof(Stick);
var field = type.GetField("m_iLength", BindingFlags.NonPublic |BindingFlags.GetField | BindingFlags.Instance);
field.SetValue(stick, -1);
Console.WriteLine(stick.Length);
Explanation:
The first line gets the Type object for Stick, so we can get the private fields later on.
The second line gets the field that we want to set by its name. Note that the binding flags are required or field will be null.
And the third line gives the field a negative value.
This question already has answers here:
Deep cloning objects
(58 answers)
How do you do a deep copy of an object in .NET? [duplicate]
(10 answers)
Closed 8 years ago.
i basically want to define a templet data object ,
and use this templet data object to assign new data objects.
then put different values to new data objects.
code like:
public class sData
{
public string name;
public int Number;
public sData(string name,int Number)
{
this.poster_path = path;
this.Number = Number;
}
}
sData templet= new sData("aaaa","0");
sData realData1 = new sData();
realData1=templet;
realData1.Number=100;
but after realData1.Number=100;
i found the templet.Number is changed to 100
how can i just give the 100 to realData1 , but no the templet ?
Am I correct in saying that you'd like to setup some a factory object which will create data objects with pre-defined set of values (i.e. a template)?
The code you have above won't do that. You have only created one object but you have two different references to it.
Perhaps something like this will do what you need:
public class sData
{
public string name;
public int Number;
public sData(string name,int Number)
{
this.poster_path = path; //copied from question, this might need updating.
this.Number = Number;
}
sData CreateCopy()
{
return new sData(name, number);
}
}
sData template = new sData("aaaa","0");
sData realData1 = template.CreateCopy();
realData1.Number=100;
This still doesn't feel very elegant, perhaps separate classes for the factory and the data object would be more appropriate, but it's hard to say without more context.
You are assigning the object variable of templet to realData1 and this way you are still referencing the same object in memory:
realData1=templet;
You can assign the values instead of the object itself:
realData1.name = templet.name;
realData1.Number = templet.Number;
Class is of reference type and the reference variables of class sData realData1 and templet point to the same memory location in heap, so the value of templet is getting overwritten by the value realData1.
my problem is as follows:
Im building a console application which asks the user for the numbers of objects it should create and 4 variables that have to be assigned for every object.
The new objects name should contain a counting number starting from 1.
How would you solve this?
Im thinking about a class but im unsure about how to create the objects in runtime from userinput. Is a loop the best way to go?
What kind of class, struct, list, array .... would you recommend. The variables in the object are always the same type but i need to name them properly so I can effectivly write methods to perform operations on them in a later phase of the program.
Im just learning the language and I would be very thankful for a advice on how to approach my problem.
If I understand your problem correctly:
class MyClass
{
public int ObjectNumber { get; set; }
public string SomeVariable { get; set; }
public string AnotherVariable { get; set; }
}
// You should use keyboard input value for this
int objectsToCreate = 10;
// Create an array to hold all your objects
MyClass[] myObjects = new MyClass[objectsToCreate];
for (int i = 0; i < objectsToCreate; i++)
{
// Instantiate a new object, set it's number and
// some other properties
myObjects[i] = new MyClass()
{
ObjectNumber = i + 1,
SomeVariable = "SomeValue",
AnotherVariable = "AnotherValue"
};
}
This doesn't quite do what you described. Add in keyboard input and stuff :) Most of this code needs to be in some kind of Main method to actually run, etc.
In this case, I've chosen a class to hold your 4 variables. I have only implemented 3 though, and I've implemented them as properties, rather than fields. I'm not sure this is necessary for your assignment, but it is generally a good habit to not have publically accessible fields, and I don't want to be the one to teach you bad habits. See auto-implemented properties.
You mentioned a struct, which would be an option as well, depending on what you want to store in it. Generally though, a class would be a safer bet.
A loop would indeed be the way to go to initialize your objects. In this case, a for loop is most practical. It starts counting at 0, because we're putting the objects in an array, and array indexes in C# always start at 0. This means you have to use i + 1 to assign to the object number, or the objects would be numbered 0 - 9, just like their indexes in the array.
I'm initializing the objects using object initializer syntax, which is new in C# 3.0.
The old fashioned way would be to assign them one by one:
myObjects[i] = new MyClass();
myObjects[i].ObjectNumber = i + 1;
myObjects[i].SomeVariable = "SomeValue";
Alternatively, you could define a constructor for MyClass that takes 3 parameters.
One last thing: some people here posted answers which use a generic List (List<MyClass>) instead of an array. This will work fine, but in my example I chose to use the most basic form you could use. A List does not have a fixed size, unlike an array (notice how I initialized the array). Lists are great if you want to add more items later, or if you have no idea beforehand how many items you will need to store. However, in this case, we have the keyboard input, so we know exactly how many items we'll have. Thus: array. It will implicitly tell whoever is reading your code, that you do not intend to add more items later.
I hope this answered some questions, and raised some new ones. See just how deep the rabbit hole goes :P
Use a list or an array. List example:
int numberOfObjects = 3;
List<YourType> listOfObjects = new List<YourType>();
for(int i = 0 ; i < numberOfObjects ; i++ )
{
// Get input and create object ....
// Then add to your list
listOfObjects.Add(element);
}
Here, listOfObjects is a Generic list that can contain a variable number of objects of the type YourType. The list will automatically resize so it can hold the number of objects you add to it. Hope this helps.
If I understood what you are asking you could probably do something like this:
class Foo
{
private static int count;
public string name;
public Foo(...){
name = ++count + "";
}
}
I'm guessing what you're trying to do here, but this is a stab in the dark. The problem I'm having is dealing with the whole "the new objects name should contain a counting number starting from 1" thing. Anyway, here's my attempt:
public class UserInstantiatedClass
{
public int UserSetField1;
public int UserSetField2;
public int UserSetField3;
public int UserSetField4;
public string UserSpecifiedClassName;
}
public static class MyProgram
{
public static void Main(string [] args)
{
// gather user input, place into variables named
// numInstances, className, field1, field2, field3, field4
List<UserInstantiatedClass> instances = new List< UserInstantiatedClass>();
UserInstantiatedClass current = null;
for(int i=1; i<=numInstances; i++)
{
current = new UserInstantiatedClass();
current.UserSpecifiedClassName = className + i.ToString(); // adds the number 1, 2, 3, etc. to the class name specified
current.UserSetField1 = field1;
current.UserSetField2 = field2;
current.UserSetField3 = field3;
current.UserSetField4 = field4;
instances.Add(current);
}
// after this loop, the instances list contains the number of instances of the class UserInstantiatedClass specified by the numInstances variable.
}
}